home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr50 / langwn23.zip / LANGWIN.DOC < prev    next >
Text File  |  1993-02-11  |  183KB  |  3,268 lines

  1. -----------------------------------------------------------------------------
  2. LangWin Version 2.3 (C) Copyright Allen L. Lang, 1993     ALL RIGHTS RESERVED
  3. -----------------------------------------------------------------------------
  4.  
  5. LangWin is a QuickBASIC program development toolkit. It contains a library of 
  6. functions and subroutines that can be used to easily create standard Graphical 
  7. User Interface (GUI) features in your compiled text-mode QuickBASIC or BASIC 
  8. PDS programs (sorry, LangWin cannot be used with the QBASIC interpreter in DOS 
  9. 5.0). 
  10.  
  11. GUI features supported include: opening/closing windows with drop-shadows, 
  12. scrollable text, push buttons, click boxes, dialog boxes, editable input 
  13. fields, etc. LangWin's GUI routines support both mouse and keyboard input. 
  14. Windows created by LangWin can be moved and resized (via mouse only). LangWin 
  15. also contains stand-alone routines that can be used to add mouse support to 
  16. your QuickBASIC programs that do not use LangWin. Mouse features include: 
  17. initialization, get/set position, get button status, hide/show cursor, set 
  18. horizontal/vertical limits, etc. Finally, LangWin has several functions that 
  19. allow you to get the default drive and directory, change the default 
  20. drive/directory, and extract all file/sub-directory names from the current 
  21. directory. All features are documented below. 
  22.  
  23.  
  24. Let's get the formalities out of the way before exploring LangWin's 
  25. capabilities ...
  26.  
  27.  
  28.  
  29. LICENSE
  30. -------
  31. All rights are reserved. LangWin is licensed free of charge. LangWin may be 
  32. copied and distributed provided: that all files are copied from this package, 
  33. as is, and in their entirety, and that no fee is charged for such copies beyond 
  34. the expense of duplication, media, and distribution. The author's rights extend 
  35. to all copies so made. Permission is granted to distribute all programs 
  36. developed using LangWin. 
  37.  
  38.  
  39. WARRANTY
  40. --------
  41. LangWin is not covered by any warranty, expressed or implied. The author will 
  42. not be liable for anything that happens as a result of any use of, or the 
  43. inability to use, LangWin in your particular application. Stated another way:
  44.  
  45.  
  46.    BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
  47.    WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
  48.    LAW. THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  49.    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED
  50.    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  51.    A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
  52.    PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM
  53.    PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  54.    REPAIR OR CORRECTION.
  55.  
  56.  
  57.  
  58.  
  59. ==========================================================================
  60.  
  61.  
  62. Phew, I hate that part. Now let's get to the good stuff: what is LangWin
  63. and how can you use it to create some great looking BASIC programs ...
  64.  
  65.  
  66.                         --------------------
  67.                         LANGWIN USER'S GUIDE
  68.                         --------------------
  69.  
  70. --------
  71. CONTENTS
  72. --------
  73.  
  74. 0.0 CHRONOLOGY OF CHANGES IN LANGWIN'S VERSIONS
  75.     0.1  Notes for Those Upgrading From Previous Versions of LangWin 
  76. 1.0 REQUIREMENTS AND RESTRICTIONS
  77. 2.0 GETTING STARTED
  78. 3.0 DOING "BASIC" WINDOWS
  79.     3.1  Initialization
  80.     3.2  Some Simple Windows
  81. 4.0 USING LANGWIN'S GUI
  82.     4.1  Close Icon
  83.     4.2  Moving, Resizing, and Minimizing the Active Window
  84.     4.3  Focus
  85.     4.4  Changing Focus (window & object focus)
  86.     4.5  Scrolling Text
  87.     4.6  Selecting Scrollable Text
  88.     4.7  Push Buttons
  89.     4.8  Check Boxes
  90.     4.9  Input Fields
  91.     4.10 No mouse
  92. 5.0 DATA STRUCTURES AND GLOBAL VARIABLES
  93.     5.1  MaxWindows
  94.     5.2  MaxButtons
  95.     5.3  MaxTextLines
  96.     5.4  MaxTextWins
  97.     5.5  AnyWinOpen
  98.     5.6  CurWinPtr
  99.     5.7  Window numbers vs window handles
  100.     5.8  SaveText
  101.     5.9  WinParms
  102.     5.10 button handles
  103.     5.11 ButtonsText
  104.     5.12 ButtonsData
  105.     5.13 UserHotKeys
  106.     5.14 WinNum
  107. 6.0 ADVANCED WINDOWS
  108.     6.1  Adding Frills to Your Windows
  109.     6.2  Window Modes, Shadows, and Movement
  110.     6.3  Using Wallpaper Windows (Info Only Window and
  111.          Multiple Lists In One Window)
  112.     6.4  Modifying Scrollable Text While Its Window Is Open
  113.     6.5  Changing The Entire Scrollable Text Array While Its Window Is Open
  114.     6.6  Modifying the Contents of an Input Field While Its Window Is Open
  115.     6.7  Determining What Had Focus When WinEvent Returns Control
  116.     6.8  Nesting Calls to WinEvent
  117.     6.9  Deactivating and Activating Buttons
  118.     6.10 Giving a Specific Button Focus When It Is Created
  119.     6.11 Is A Given Window Open
  120.     6.12 Manually Giving a Window Focus (i.e., via program control)
  121.     6.13 State of Check Boxes
  122.     6.14 Run Time Errors
  123.     6.15 Testing for Color, B/W, EGA, or VGA 
  124.     6.16 Colors, Attributes, and Palettes
  125.     6.17 WaitTicks
  126.     6.18 Video Pages
  127.     6.19 Using Non-Text Mode Graphics With LangWin
  128.     6.20 Closing Windows
  129.     6.21 Modifying Static Text Created With ShowWinText
  130.     6.22 "Time Out" Feature of WinEvent for Interrupt Buttons 
  131.     6.23 Dynamically Adding Entries to a Visible List of Scrollable Text
  132. 7.0 MOUSE ROUTINES
  133. 8.0 DIRECTORY AND FILE ROUTINES
  134. 9.0 COMING ATTRACTIONS
  135. 10.0 CONTACTING THE AUTHOR
  136.  
  137.  
  138.  
  139. -----------------------------------------------
  140. 0.0 CHRONOLOGY OF CHANGES IN LANGWIN'S VERSIONS
  141. -----------------------------------------------
  142. You're right! I added this section after the user's guide was complete, and I 
  143. didn't feel like re-numbering all following sections (I'm using a plain vanilla 
  144. text editor). So, this section gets number zero. I guess that means the next 
  145. section that needs to be inserted must have a negative number! 
  146.  
  147. Major changes implemented in LangWin's Versions:
  148.  
  149. 1.0   Never released. Finally got LangWin packaged, but I thought of too many 
  150.       additional features that I wanted to include. [2/92]
  151.  
  152. 1.1   First version of LangWin released. [4/28/92]
  153.  
  154. 1.2   - Simplified the license statement.
  155.       - Updated Section 6.5 of user's guide.
  156.       - Significant performance improvement in window open/close by
  157.         writing/reading directly to/from video buffer (DEF SEG=&HB800).
  158.         (so don't relocate/reuse the upper memory block at segment &HB800).
  159.         [5/23/92]
  160.  
  161.  
  162. 2.0   Major re-write. Removed the restriction that "locked" the mouse onto
  163.       the current window. With 2.0, you can open multiple windows, mouse
  164.       to any visible window, click on any button, scroll any text, etc.
  165.       (rather than being restricted to just the current window in focus). 
  166.       I've also added several new window features such as shadowless,
  167.       unmovable, modal (you must close it before any other window can be 
  168.       selected), immediate close (clicking on another window will automatically
  169.       close it), and wallpaper (background only). These new features require
  170.       a slightly different programming technique than LangWin 1.x, so most
  171.       code developed for LangWin 1.x will need to be updated (new calling
  172.       parameters for some routines and slightly new logic in the WinEvent
  173.       loop). Sorry, but after you start using 2.0, I think you'll agree 
  174.       that the hassle of re-coding was worth the new features provided.
  175.       The new features are described in this User's Guide.
  176.  
  177.       Both QuickBASIC and BASIC PDS are now supported. 
  178.  
  179.       I've also moved the online documentation for all LangWin's routines
  180.       from a stand-alone program (which required you to exit QB and run the
  181.       program to get info on a particular routine), to a module (WINHELP.BAS) 
  182.       that can be loaded into QB with your program under development. Thus, 
  183.       you need only hit the F2 key while developing with LangWin in the QB 
  184.       environment to get online help for any routine. 
  185.       [10/25/92]
  186.  
  187. 2.1   Window resizing and minimizing added.
  188.       
  189.       ChangeButtonFocus routine added to allow a specific object to be given
  190.       focus when a window is first opened (i.e., creating a default button). 
  191.       Section 6.10 has more details and examples.
  192.       
  193.       Some parameters in LangWin's data structures were changed
  194.       (section 5.0 has most current description).
  195.  
  196.       ActivateButton routine no longer needs a string variable with the 
  197.       Buttons's text. The Button's original text is remembered when it is
  198.       deactivated (DeactivateButton) and automatically restored. 
  199.       If converting from V2.0, remove the string parameter from calls
  200.       to ActivateButton or you'll get a parameter mismatch error.
  201.       [11/21/92]
  202.  
  203. 2.2   Fixed misc bugs.
  204.         - Buttons at top of screen could not be moved or resized.
  205.         - When minimizing and restoring window to original size,
  206.           window would be 2 columns larger than original.
  207.         - Code in WinEvent required left mouse button to be down
  208.           at the actual time the mouse was polled (in order to "recognize" a 
  209.           click on the left button). On slow machines, it was possible
  210.           for the left button to have been clicked and released at the point in
  211.           time when the mouse was polled. Symptom was that left mouse button
  212.           was ignored. Code now only tests to determine if left mouse
  213.           button had been pressed any time since the last time mouse was polled
  214.           (current state of the left button at the time the mouse is polled
  215.           is no longer tested). The state of the right button is still 
  216.           tested at the time the mouse is polled (to distinguish between
  217.           a left click, a right click, and both buttons clicked).
  218.  
  219.       The mouse remains active when an input field is selected for data entry.
  220.         - Mouse can be used to place text cursor anywhere in the input field.
  221.         - Mouse can be used to exit input mode by clicking anywhere outside
  222.           the input field (including clicking on wallpaper, another window,
  223.           another button, another inputfield, etc.). 
  224.  
  225.       The input field can be used for password entry. All text entered will
  226.       be displayed with the * character; the actual text entered will be 
  227.       saved in ButtonsText(handle) - just as any input field's text.
  228.       Use a negative value for the input field's length (in MakeInputField) to
  229.       cause the input field to be used in this way. An alternative
  230.       technique, available in previous releases, would be to define the input
  231.       field with the same values for foreground and background colors. In this
  232.       case, nothing will be visible when text is entered.
  233.       [12/12/92]
  234.  
  235.  
  236. 2.3   Several new hints & tips were added to Section 6.0 (Advanced Windows)
  237.       of this User's Guide (i.e., 6.18 - 6.23); other sub-sections were updated
  238.       (6.3.2 and 6.16). Previous users of LangWin should scan all of 
  239.       Section 6.0 and read the new sub-sections. 
  240.  
  241.       A new option ("time out") was added to WinEvent. With the time out option
  242.       enabled, WinEvent will automatically return control to your program after
  243.       0.5 sec if no events are detected. The time out option can be used to 
  244.       implement an "interrupt" button for long running tasks. See Section 6.22
  245.       and SAMPLE05.BAS for additional details and sample code.
  246.  
  247.       A new function was added (GrowScrollText) that allows you to dynamically
  248.       add entries to a visible list of scrollable text (i.e., after the
  249.       scrollable text window has been opened). This can be used to 
  250.       give the user real-time feedback while a long running task is underway.
  251.       For example, suppose you are searching an entire hard disk for all files
  252.       that match a given specification. As each file name is found, it can be
  253.       added to a visible list of scrollable text in the current window.
  254.       Section 6.23 contains additional details and SAMPLE05.BAS illustrates
  255.       the use of GrowScrollText.
  256.  
  257.       Most of the SAMPLE programs included on the distribution disk were 
  258.       cleaned up. Standard code is used in the main modules to initialize
  259.       (see Section 3.1 for examples). SAMPLE04.BAS was re-written (it still
  260.       performs the same task). SAMPLE05.BAS is new with V2.3.
  261.  
  262.       The GetFileNames function (see Section 8.0) has been modified.
  263.       This functions places all file or directory names that match a specific
  264.       criteria into a string array (whose name is passed as a parameter). 
  265.       Previously, this string array had to be DIMed to a given size, and
  266.       if the array was filled, an error code was returned. With V2.3, the
  267.       size of string array is automatically adjusted by GetFileNames to
  268.       hold all of the names that match the given criteria. The string array,
  269.       however, MUST be DYNAMIC or a "duplicate definition" error will occur. 
  270.       In addition, a new option was added to GetFileNames. Previously, only
  271.       "regular" file or directory names could be extracted (i.e., not 
  272.       read only, hidden, or system). The new option allows ALL names that
  273.       match the criteria to be extracted (both files and directories). In this
  274.       case, the name is prefixed with a one byte string containing the value of
  275.       the file or directory's attribute. The bits in this byte can be tested to
  276.       determine whether the name corresponds to a file or directory, and 
  277.       whether it's regular, hidden, system, read-only, etc. Before displaying
  278.       the name, the attribute byte must be removed, otherwise you'll get some
  279.       strange values as the file or directory's first character. See 
  280.       WINHELP.BAS for more details on the GetFileNames function along with a
  281.       description of the attribute byte.
  282.  
  283.       OpenScrollWindow has been modified. This function displays the contents
  284.       of a string array in a scrollable window. In previous releases, if
  285.       UBOUND of this array was greater than the MaxTextLines global variable,
  286.       a run-time error would terminate your program when OpenScrollWindow
  287.       was called. As of V2.3, if UBOUND of the string array > MaxTextLines,
  288.       then only the first MaxTextLines of the array will be displayed
  289.       (run-time error will not occur). To let your user know that this
  290.       condition has occurred, the last line in the scrollable window will
  291.       be set to the string:    "(Incomplete List)"
  292.  
  293.       RefreshScrollText has been modified. This subroutine is used to 
  294.       dynamically change the scrollable text displayed in a window created via
  295.       OpenScrollText. A string array is passed to RefreshScrollText which 
  296.       contains the new scrollable text to be placed into the current window. 
  297.       Similar to the modification made to OpenScrollWindow mentioned above, 
  298.       if UBOUND of this string array is greater than MaxTextLines, then only 
  299.       the first MaxTextLines will be displayed with the last line set to the 
  300.       string:   "(Incomplete List)". A run-time error will no longer be 
  301.       generated if UBOUND of the string array is greater than MaxTextLines.
  302.  
  303.       When moving a window, you can no longer attempt to place it off of the
  304.       screen (which used to cause an error message to be displayed). When
  305.       moving a window (by dragging upper left corner with left mouse button),
  306.       the mouse cursor will be limited (can't be moved off of the screen).
  307.       If the window has a shadow, the limit set for the mouse cursor will
  308.       have two columns on the right and one row at bottom reserved for
  309.       the area where a shadow will be displayed.
  310.  
  311.       Any video page available on your system can now be used with LangWin
  312.       (previous versions of LangWin only supported page 0); however, the  
  313.       SAME video page MUST be used for all windows/objects created with 
  314.       LangWin. See Section 3.1 for a discussion on initializing the video 
  315.       page with the SCREEN command, and see Section 6.18 for a discussion 
  316.       on using video pages. With V2.3, you MUST place the SCREEN command
  317.       BEFORE the call to LangWinInit (Section 3.1 has more details).
  318.  
  319.       In some cases, moving small (e.g., minimized) windows could result in the
  320.       lower right "move" cursor not being erased. This bug was corrected (it 
  321.       was never reported, I found it when testing the new code to support
  322.       video pages beyond page 0). The bug was caused by not hiding the mouse
  323.       cursor before doing i/o to the screen (i.e., you can't change the 
  324.       character "under" the mouse cursor without first hiding the cursor). 
  325.       After finding the above bug, I looked for other similar problems caused
  326.       the same omission (i.e., not hiding the mouse cursor prior to writing to
  327.       the screen). RefreshScrollText had a similar bug. If the mouse cursor 
  328.       happened to be at the very top of the scroll slider area, then the
  329.       contents of the screen "underneath" the mouse cursor would not be updated
  330.       correctly when the text was refreshed. This bug was also corrected.
  331.  
  332.       The DeactivateButton routine (introduced in V2.0) can be used to make a 
  333.       button "inactive". The button will still appear in the window, but its
  334.       text will be cleared, and it cannot be selected (until reactivated with
  335.       the ActivateButton routine). If a window with an "inactive" button was
  336.       resized by moving the right side of the window to the left, the inactive
  337.       button's length was incorrectly computed, and in some cases the inactive
  338.       button could end up being displayed beyond the right boundary of the 
  339.       resized (smaller) window. This bug was fixed. When a window is made
  340.       smaller, all objects will be compressed, and will eventually "disappear"
  341.       if the window is made small enough (they will reappear when the window is 
  342.       enlarged). 
  343.       
  344.       The Page-Down key can be used to display the next page of a scrollable
  345.       list of text. However, if the actual scrollable list had fewer rows than 
  346.       the area allocated for scrollable text when the window was opened, and
  347.       the Page-Down key was used, the text was not displayed correctly. The 
  348.       last physical line of the text area, rather than the last line of actual
  349.       text, was highlighted. This highlight then remained on the screen after
  350.       a subsequent Page-Up. This bug has been fixed.  
  351.  
  352.       Successive calls to ActivateButton would actually toggle between the 
  353.       active/deactive state. Similarly for successive calls to 
  354.       DeactivateButton. These bugs have been fixed. Now, successive calls to 
  355.       ActivateButton (DeactivateButton) will all result in the button 
  356.       remaining active (inactive). 
  357.  
  358.       [3/20/93]
  359.  
  360. 0.1 Notes for Those Upgrading From Previous LangWin Versions
  361. ------------------------------------------------------------
  362. This section contains some information that is repeated from the previous 
  363. section. For those who read the documentation from "cover to cover", please 
  364. excuse the repetition. For others who skip around, I've included some of the
  365. key changes (as described in the previous section):
  366.  
  367. For LangWin 1.x users: one change you'll have to deal with is that several 
  368. routines now have additional calling parameters, failure codes are negative 
  369. (i.e., in cases of failure, the value returned is the same as in V1.x, but the 
  370. number is negative rather than positive), and some new failures are detected. 
  371. Load the online help facility (WINHELP.BAS) into QB and scan the documentation 
  372. for each routine. I've tried to include a "V2.0 Changes" section to help you 
  373. spot them. Routines that should be examined for changes include: BlankWin, 
  374. OpenScrollWindow, WinEvent, ReShowText, and ReShowPage. New routines include: 
  375. NewFocusWindow, RefreshScrollText, IsWinOpen, ActivateButton, DeactivateButton, 
  376. ChangeDir, ChangeDrive, GetCurDir$, GetCurDrive$, and GetFileNames. Be sure to 
  377. scan ALL routines in WINHELP.BAS to review new features, functions, parameters, 
  378. return codes. 
  379.  
  380. Another change for V1.x users is that it requires a slightly different (easier) 
  381. programming technique. With 1.x, you needed a separate call to WinEvent for 
  382. each window opened. Starting with 2.0, you can get by with one call to WinEvent 
  383. for your entire program! Although, for complex programs with many menus and 
  384. nested windows, you might want to have a separate subroutine for each menu, 
  385. with one call to WinEvent in each subroutine. Be careful not to nest calls to 
  386. WinEvent too deep or you'll run out of BASIC's stack space. 
  387.  
  388. Starting with v2.0, BlankWin and OpenScrollWindow now return a unique NUMBER 
  389. associated with the window created (in V1.x, these routines returned a handle, 
  390. see Section 5.7 for a discussion of the difference between these two concepts). 
  391. This number will be used to determine which window had focus when an event 
  392. occurred. As in V1.x, save the value returned by these routines in a unique 
  393. variable for each window. 
  394.  
  395. WinEvent handles all scrolling, mouse, and keyboard events. Starting with V2.0, 
  396. WinEvent will detect when you mouse to a different window and click on it. In 
  397. this case, the new window will be given "focus" (by making visible any hidden 
  398. parts of the new window that are "under" other overlapping windows). When you 
  399. click on an object (button, scrollable text, close icon), WinEvent makes the 
  400. corresponding window current (gives it focus). In addition, the WinEvent 
  401. function returns a value equivalent to the number of the window with focus 
  402. (this is the number assigned to the window when it was created by BlankWin or 
  403. OpenScrollWindow). WinEvent takes one output parameter which is set to an code 
  404. that defines the type of action that was selected in the window (1=close; 
  405. 2=scrollable text selected; 3=button selected). The action code parameter is 
  406. given the same value that the WinEvent function itself returned in LangWin 1.x. 
  407. Between the window number and action code returned, you can determine what 
  408. event took place and where it happened.   
  409.  
  410. With LangWin 2.0, several new window modes are supported. See Section 6.2 for 
  411. details. 
  412.  
  413. With LangWin 2.0, both QuickBASIC and BASIC PDS are supported.
  414.  
  415. With V2.1, you can now resize and minimize windows (see section 4.2). In order 
  416. to implement this function, non-scrollable text (created with ShowWinText) has 
  417. to be saved in LangWin's data structures (so it can be re-displayed). The 
  418. MaxButtons global variable (see sections 3.1 and 5.2) must now be large enough 
  419. to not only count all buttons, but also all lines of non-scrollable text. If 
  420. you are converting from a previous version of LangWin, it's likely that you'll 
  421. have to increase the value of MaxButtons (by the number of lines of non-
  422. scrollable text that could be simultaneously visible on all open windows). 
  423. If MaxButtons is not large enough, the corresponding "make" routines that 
  424. create objects will return an error code. New with V2.1, ShowTitle and 
  425. ShowWinText will also return a code if there's no room in the data structures 
  426. to save the corresponding title or static text. If you do not check for these 
  427. error codes, the symptom you'll see is that objects you expect to see (buttons, 
  428. static text, titles, etc.) will not be visible. 
  429.  
  430. With V2.1, ActivateButton routine no longer needs a string variable with the 
  431. Buttons's text. The Button's original text is remembered when it is deactivated 
  432. (DeactivateButton) and automatically restored when activated. If you used the 
  433. ActivateButton routine in LangWin 2.0, just remove the string variable from the 
  434. calling parameter list (otherwise you'll get a parameter mismatch error). If 
  435. you used the string variable in ActivateButton to change the button's text 
  436. prior to activating, my apologies (you can't do that anymore) but that's not 
  437. how the parameter was intended to be used. If you need to change the button's 
  438. text prior to activation, then change the contents of ButtonsText(han), where 
  439. han is the button's handle. Be careful not to make the button's new text longer 
  440. than the original button's length - which is saved in ButtonsData(han,4). See 
  441. Section 5.11 for additional details on the button's text. 
  442.  
  443. With V2.3, you MUST place the SCREEN command BEFORE the call to LangWinInit.
  444. See Section 3.1 for additional details.
  445.  
  446. With V2.3, OpenScrollWindow and RefreshScrollText no longer generate run time 
  447. errors if UBOUND of string array (containing scrollable text) is greater than 
  448. MaxTextLines (i.e., the maximum number of text lines DIMed in LangWin's data
  449. structures - see Section 3.1 for details on defining MaxTextLines). Instead,
  450. the number of text lines displayed will be truncated to (MaxTextLines - 1), and
  451. the last line displayed will appear as:       "(Incomplete List)"
  452. Note that the contents of the string array are NOT modified, only the last line 
  453. displayed in the scrollable text window is changed. Prior to calling 
  454. OpenScrollWindow or RefreshScrollText, you can compare UBOUND of the string
  455. array to MaxTextLines to detect this condition (or just allow the text lines
  456. displayed to be truncated - in which case no special return code is provided). 
  457.  
  458. With V2.3, a new option has been added to GetFileNames. Previously, 
  459. GetFileNames only returned "regular" file or directory names (i.e., not those 
  460. that were read-only, hidden, or system). The new option will return ALL names 
  461. (that match the file specification) along with an attribute byte (which is 
  462. included as the first character of the name). You must test the bits of this 
  463. attribute byte to determine if the name is a file or directory, and if it's 
  464. regular, hidden, system, read-only, etc. Then, before displaying the name, you 
  465. must remove the attribute byte (or the first character of the name will look 
  466. very funny). See the GetFileNames member in WINHELP.BAS for more details, along 
  467. with a description of the bits within the attribute byte. 
  468.  
  469. With V2.3, GetFileNames will automatically REDIM the array passed to hold all 
  470. names that match the file specification. Previously, the array had to be pre-
  471. DIMed large enough to hold all names (or an error code was returned if the 
  472. array was not large enough). Now, just pass an array that has been DIMed (1) 
  473. and GetFileNames will re-adjust the array to the correct size. Note, the array 
  474. MUST be DYNAMIC. LBOUND of the returned array will be 1. See WINHELP.BAS for
  475. more information.  
  476.  
  477. With V2.3, a new option ("time out") was added to WinEvent. With the time out 
  478. option enabled, WinEvent will automatically return control to your program 
  479. after 0.5 sec if no events are detected. The time out option can be used to 
  480. implement an "interrupt" button for long running tasks. See Section 6.22 and 
  481. SAMPLE05.BAS for additional details and sample code. 
  482.  
  483. With V2.3, a new function was added (GrowScrollText) that allows you to 
  484. dynamically add entries to the bottom of a visible list of scrollable text 
  485. (i.e., after the scrollable text window has been opened, you can append text). 
  486. This can be used to give the user real-time feedback while a long running task 
  487. is underway. For example, suppose you are searching an entire hard disk for 
  488. all files that match a given specification. As each file name is found, it can 
  489. be added to a visible list of scrollable text in the current window. Section 
  490. 6.23 contains additional details and SAMPLE05.BAS illustrates the use of 
  491. GrowScrollText. 
  492.  
  493.  
  494.  
  495.  
  496. Within this user's guide and the online help (WINHELP.BAS), I've tried to 
  497. include the corresponding LangWin version numbers when describing new 
  498. features/functions. Users of previous LangWin versions can scan for appropriate 
  499. character strings (i.e., 2.0, 2.1, etc.) to quickly find changes. However, I 
  500. would still encourage previous users to read this ENTIRE guide and ALL members 
  501. in WINHELP.BAS since, in many cases, entire sections have been re-written. 
  502.  
  503.  
  504. ---------------------------------
  505. 1.0 REQUIREMENTS AND RESTRICTIONS
  506. ---------------------------------
  507. LangWin is a GUI toolkit for QuickBASIC or BASIC PDS developers. You must have 
  508. one of these compilers to use LangWin.
  509.  
  510. Programs developed with LangWin are meant to run under DOS (see Windows 
  511. restriction later in this section). I developed LangWin using DOS 4.01 and did 
  512. some testing with DOS 5.0. LangWin was developed entirely in QuickBASIC, so it 
  513. should be compatible with earlier versions of DOS (but I did not do any 
  514. explicit testing with earlier DOS versions). 
  515.  
  516. LangWin creates color text-mode (SCREEN 0) windows. You must have a color 
  517. monitor with EGA graphics or better (but also see Section 6.19). 
  518.  
  519. A mouse is not required to take advantage of LangWin's GUI features, but
  520. as you probably know, using any GUI from the keyboard PAINFUL!
  521.  
  522. LangWin is a quick library. It is object code, NOT source. (You CANNOT use 
  523. LangWin with DOS 5.0's QBASIC interpreter). I used QB 4.5 to develop LangWin 
  524. (which was written ENTIRELY in QuickBASIC to demonstrate how powerful this 
  525. language really is). LangWin is very similar to the User Interface (Menu, 
  526. Window, Mouse, and General) routines included with the BASIC Professional 
  527. Development System (PDS) V7.1. Actually, I think LangWin is easier to use, but 
  528. I might not be totally objective in my assessment! 
  529.  
  530. Since the release of V2.0, there have been two "flavors" of LangWin's 
  531. libraries: one for QuickBasic (called LANGWIN.QLB and LANGWIN.LIB) and one for 
  532. BASIC PDS (called LANGWINP.QLB and LANGWINP.LIB). As previously mentioned, I 
  533. did all of my development and testing in QuickBASIC 4.5. I created the PDS 
  534. libraries and ran the samples under PDS 7.1, but I've not done extensive 
  535. testing in PDS, nor have I taken advantage of any PDS specific features 
  536. (LangWin source compiled clean under PDS the first time with no changes 
  537. required between the two flavors - except changing VARPTR to SSEG for variable 
  538. length strings). Beginning with LangWin V2.3, the compressed set of 
  539. distribution libraries were too large to fit on a 360K diskette. So I decided 
  540. to omit the PDS libraries (since most people have QuickBASIC). If the 
  541. distribution of LangWin that you have does not include the PDS libraries 
  542. (LANGWINP.*), and you would like the PDS versions, please contact me and I'll 
  543. send you a copy. 
  544.  
  545. VBDOS? Serious competition for LangWin, but no comparison when you consider the 
  546. price (LangWin is free). I did load the sample programs and LangWin source into 
  547. the VBDOS environment and ran them successfully (no modifications were 
  548. required except for the VARPTR to SSEG changes made for PDS). I have not 
  549. included a VBDOS compatible quick library with this distribution. I'd be 
  550. flattered by anyone requesting a VBDOS compatible LangWin quick library, but in 
  551. that case: save the cost of VBDOS, keep QB or PDS, and use the quick libraries 
  552. included with this release. If you're gonna use VB, go ahead and use the GUI 
  553. tools that come with it (I'm considering some VB-like interactive graphical 
  554. tools for LangWin 3.0). 
  555.  
  556. Windoze? LangWin's mouse interface will not work properly if DOS is run in a 
  557. window (not really a LangWin restriction, but the Int 33h interface to standard 
  558. DOS mouse drivers does not work in Windows which has its own mouse driver). So 
  559. if the code you develop with LangWin will be run in a Windows environment, and 
  560. you want to take advantage of LangWin's mouse interface, then you must load a 
  561. standard DOS mouse driver when you boot (via CONFIG.SYS or AUTOEXEC.BAT) BEFORE 
  562. starting WIN, and your code must run in full screen DOS under Windows, it 
  563. cannot run in a DOS window. This should not be a major restriction, but if you 
  564. must run in a DOS window, consider VBWIN for your development. 
  565.  
  566. When using the LangWin quick library with the QB environment to develop code, 
  567. the more free (as opposed to installed) main memory you have the better. QB 
  568. consumes a certain amount of main memory when run. LangWin uses dynamic string 
  569. arrays and many string variables. Between the memory consumed by the QB 
  570. environment itself, and LangWin's strings, it is possible to encounter an "out 
  571. of string space" or "out of memory" message while developing under QB with the 
  572. LangWin library. (I developed LangWin in OS/2's DOS box which only had 470K 
  573. free on my system and often ran out of string space. When booting DOS, which 
  574. had 570K free, I did not have a problem). 
  575.  
  576. You may not see a string space problem while developing unless your programs 
  577. get very large, have lots of comments, or use lots of strings. This is a 
  578. QuickBASIC environment restriction and relates to how much main memory QB 
  579. itself takes while loaded, and how it stores and manages strings. It's a good 
  580. idea to free up as much main memory as possible before calling the QB 
  581. development environment. Use the FRE (-1) and FRE ("A") commands from QB's 
  582. immediate window to determine the amount of free memory you have left from 
  583. within the QB environment. If you get an "out of string space"  or "out of 
  584. memory" message while developing in the QB environment, use CLEAR in the 
  585. immediate window to reset all variables. If this does not help, save your code, 
  586. exit QB, and start QB again. If you still get "out of memory" or "out of string 
  587. space" try the following: reduce value of MaxWindows, reduce the "rows" 
  588. parameter in your WIDTH command, reduce the value of MaxTextWins, UNLOAD the 
  589. WINHELP module if it was loaded for online help (see the DOING "BASIC" WINDOWS 
  590. Section for more details). Programs compiled with the LangWin library will be 
  591. large (over 60K), but should not have a string space problem while running (of 
  592. course this too will depend upon how big your EXE is and how much free memory 
  593. you have). 
  594.  
  595. LangWin allows up to 16 attributes (0-15) to be specified for colors. In order 
  596. to obtain 16 unique background attributes (usually there are only 8), blinking 
  597. foreground colors are disabled. This requires that foreground/background 
  598. attribute numbers be translated before using the COLOR command. Thus, when 
  599. using LangWin, your should NOT use the COLOR command directly in your code to 
  600. set foreground/background attributes. Instead, use LangWin's SetColor routine 
  601. (load WINHELP.BAS into QB to see details on all LangWin's routines). SetColor 
  602. takes two parameters (foreground and background attributes, between 0 and 15). 
  603. It will translate these appropriately and issue the COLOR command itself. If 
  604. you use the COLOR command instead of SetColor, you may get some unexpected 
  605. colors. Also see Section 6.15 for more information on colors in LangWin.
  606.  
  607. As of LangWin Version 1.2, a significant improvement in the speed of window 
  608. creation (open) and deletion (close) has been achieved by writing directly to 
  609. the video buffer (DEF SEG=&HB800). While the increase in speed is a benefit, 
  610. there are some disadvantages in writing directly to the buffer (rather than 
  611. using the standard DOS services). For example, if the location of the video 
  612. buffer were to move, LangWin would not know it and over-write whatever did 
  613. exist in the segment located at &HB800. Since many software products write 
  614. directly to the video buffer to improve performance, it's not too likely that 
  615. future releases of DOS will deliberately move the buffer. However, with DOS 5.0 
  616. (and several other memory management products), one can reuse upper memory 
  617. blocks (for TSRs, etc.) in order to free up as much of the first 640K as 
  618. possible. I haven't tried it, but I suppose it's possible to reuse the block 
  619. located at segment &HB800. In any case, if you do reuse the block at segment 
  620. &HB800, LangWin 1.2 (or later versions) will not work. 
  621.  
  622.  
  623.  
  624. -------------------
  625. 2.0 GETTING STARTED
  626. -------------------
  627. Before you can begin developing with the LangWin quick library, you must place 
  628. LANGWIN.BI (include file), LANGWIN.QLB and LANGWIN.LIB (libraries) on your 
  629. hard disk, and tell QB where these files are (via the Options; Set Path menu). 
  630. I recommend placing them in the same directory as your other QuickBASIC  
  631. include files and libraries. LANGWIN.QLB contains QB.QLB and LANGWIN.BI 
  632. contains QB.BI. If your code defines a user data type as RegType or RegTypeX 
  633. and calls INTERRUPT or INTERRUPTX, you won't need to do anything extra beyond 
  634. using LangWin. 
  635.  
  636. With V2.0, LANGWINP.QLB and LANGWINP.LIB are corresponding files for PDS; 
  637. LANGWIN.BI can be used for both QB and PDS. If you are using LangWin with PDS, 
  638. the following instructions also apply, just issue the corresponding PDS 
  639. commands, etc. 
  640.  
  641. Select Options from the QB main menu, and Set Paths from the Options menu. 
  642. You'll see the current paths for executable, include, library, and help files 
  643. (these may all point to the same directory). You can then quit QB and place the 
  644. corresponding LangWin files into your defined directories for include files and 
  645. libraries. If your QB environment has no paths defined, then update the Set 
  646. Paths menu and place LangWin's file and libraries into the corresponding 
  647. directories. (For a quick start, just place the LangWin files in a working 
  648. directory and call QB  /ah /L langwin from that directory.) 
  649.  
  650. Once you have told QB where the LangWin files are (you'll only need to do this 
  651. once), then call the QB environment from your DOS prompt as follows (I assume 
  652. that "qb" is the name of your QB.EXE file and the directory where it resides 
  653. is on your DOS PATH): 
  654.  
  655.         qb /ah /L langwin       (qbx /ah /L langwinp for PDS)
  656.                             
  657. The /ah parameter tells QB to allow dynamic arrays > 64K in size
  658. (it takes a lot of memory to save screen contents when opening windows).
  659.  
  660. The /L langwin parameter tells QB to load the LangWin quick library
  661. (see your QuickBASIC manual for more information on Quick Libraries).
  662.  
  663. See Section 3.1 (and the sample programs distributed with LangWin) for typical 
  664. initialization code needed for LangWin. 
  665.  
  666. I've included the contents of QB.BI in LANGWIN.BI and the contents of QB.QLB in 
  667. LANGWIN.QLB, so you DO NOT need to load the QB versions of these files 
  668. (similarly for the corresponding PDS libraries, they are included in LANGWIN.BI 
  669. and LANGWINP.QLB). If you used QB.BI and QB.QLB to call interrupts from your 
  670. QuickBASIC programs, all you'll need is the LangWin files and you'll still
  671. be able to call interrupts.
  672.  
  673. -------------------------
  674. 3.0 DOING "BASIC" WINDOWS
  675. -------------------------
  676. Once you have called the QB environment with the LangWin library, you're ready 
  677. to begin doing windows. I'll cover "basic" windows in this section, and more 
  678. advanced techniques in a later section. 
  679.  
  680. Note that most references to LangWin's routines in this document do not include 
  681. a complete description of the corresponding parameters and return codes. This 
  682. document attempts to show the concepts necessary to create a GUI environment 
  683. using LangWin. For a detailed description of every LangWin routine, including 
  684. parameters and return codes, load WINHELP.BAS (new with V2.0; included on your 
  685. distribution disk) into QB and hit F2. You can select any LangWin routine and 
  686. examine corresponding documentation. In order to reference the online help 
  687. routines, first OPEN an existing module under development (or create a new 
  688. one). Then select LOAD and load the WINHELP.BAS module (don't forget to UNLOAD 
  689. the WINHELP module before compiling your code!). While developing, if you need 
  690. to reference documentation for LangWin, just hit F2 and select the routine you 
  691. need. Routine names in WINHELP will end with a period, this is only to avoid 
  692. conflicts with the "real" routine names in LangWin. When you code the routine's 
  693. name, do not include the period. If you get "out of string space" or "out of 
  694. memory" errors, you may have to UNLOAD the WINHELP module. 
  695.  
  696. 3.1 Initialization
  697. ------------------
  698. Before you can call LangWin's routines, they must be DECLARED, global arrays 
  699. and variables must be initialized, the screen must be set to text mode, and 
  700. the mouse (if it exists) must be initialized. Here's some sample code to 
  701. accomplish this (just copy this to start a program that will use LangWin): 
  702.  
  703. '===========================================================================
  704.  
  705. '$DYNAMIC  make all arrays dynamic
  706.  
  707. DEFINT A-Z
  708.  
  709. ' optional: test to see if color EGA or VGA monitor is present.
  710. ' see Section 6.16 for techniques to accomplish these tests.
  711.  
  712.  
  713.  
  714. '$INCLUDE: 'LANGWIN.BI' ' TYPE, DECLARE and COMMON definitions for LangWin.
  715. '                         NOTE: LANGWIN.BI contains all definitions found
  716. '                               in QB.BI, so include for QB.BI is not needed.
  717. '                               (similarly for QBX.BI in PDS).
  718.  
  719. ' the following sets the stack at 9000 bytes. if the stack is not large enough
  720. ' you'll get some very strange errors. 9000 bytes should be large enough,
  721. ' but if you are in doubt, print the value of FRE(-2) to dynamically determine
  722. ' available stack space while your program is running.
  723.  
  724. CLEAR , , 9000   ' set stack to 9000 bytes
  725.  
  726.  
  727. ' the following is not required by LangWin, but will let you determine
  728. ' the screen colors at the time your program was called, and re-establish
  729. ' those same colors after your program terminates.
  730.  
  731. ' get attribute from current screen so it can be restored upon exit
  732. OrigAttr = SCREEN(1, 1, 1)' save original attribute from row 1, col 1
  733.  
  734.  
  735. ' if WIDTH command is used, it must be placed BEFORE call to LangWinInit.
  736. ' code in LangWinInit extracts max rows/cols from screen and saves
  737. ' in global variables (MaxCols and MaxRows). if WIDTH is used to change screen
  738. ' after LangWinInit has determined the screen's row/col dimensions, your 
  739. ' windows won't work!
  740.  
  741. WIDTH 80, 25
  742.  
  743. ' these variables MUST be defined BEFORE call to LangWinInit.
  744. ' i've used sample values to define these variables. 
  745. ' you should change these values to meet the requirements of the program
  746. ' you are writing, BUT keep these as low as possible 
  747. ' to conserve memory at run time (see comments below for explanations).
  748.  
  749. MaxWindows = 5       ' max simultaneous open windows
  750. MaxButtons = 10      ' max number of objects (including non-scroll text) active
  751. ' following two variables are new with V2.0:
  752. MaxTextLines = 35    ' maximum number of text lines in any scrollable win
  753. MaxTextWins = 3      ' max windows that can have scrollable text
  754.                      ' must be <= MaxWindows
  755.  
  756.  
  757. LOCATE , , 0             ' start with hidden text cursor
  758.  
  759.  
  760. ' LangWin only supports text mode. You MUST call the SCREEN 0 command BEFORE
  761. ' the call to LangWinInit. You can call SCREEN with a video page other than 0
  762. ' (i.e., SCREEN 0,,x,x   where x is a page number supported by your system).
  763. ' Code in LangWinInit will determine which video page you are using and save
  764. ' the value in a global variable for use by other LangWin routines. If you 
  765. ' call SCREEN 0 after LangWinInit and change the original video page, you'll
  766. ' get unpredictable results (i.e., LangWin will write to the original video 
  767. ' page). However, you can use other video pages for functions not associated
  768. ' with your LangWin windows; just be sure to set the video page back to the
  769. ' original value defined below.
  770.  
  771. SCREEN 0,,0,0           ' LangWin ONLY supports text mode 
  772.                         ' You MUST call the SCREEN command BEFORE LangWinInit
  773.  
  774.  
  775. CALL LangWinInit  ' initialize (if mouse exists, it will be displayed)
  776.  
  777.   ' if you get "subscript out of range" error while
  778.   ' in LangWinInit, be sure you called QB with /ah.
  779.   ' then try reducing the value of MaxWindows.
  780.   ' check the WIDTH command; reduce number of rows.
  781.  
  782.  
  783. ' display "wallpaper"   (background for windows)
  784.  
  785. IF HaveMouse THEN CALL HideMouseCursor  ' first hide mouse pointer
  786. CLS
  787. CALL SetColor(4, 15) ' pick any colors you like (run WINCOLOR for samples) 
  788. FOR i = 1 TO MaxRows ' paint the screen
  789.  LOCATE i,1
  790.  PRINT STRING$(80, 178); ' can try 176, 177, or 178 to get different effects
  791. NEXT
  792. IF HaveMouse THEN CALL ShowMouseCursor   ' display the mouse pointer
  793.  
  794. '====================
  795. ' YOUR CODE GOES HERE
  796. '====================
  797.  
  798. IF HaveMouse THEN HideMouseCursor    ' we're done with the mouse
  799.  
  800. ' now restore original screen colors before terminating
  801. bbb = (OrigAttr AND &HF0) \ 16  ' mask & shift to get original background
  802. fff = OrigAttr AND &HF          ' mask to get original foreground
  803. PALETTE                           ' restore original palette
  804. CALL SetColor(fff, bbb)           ' restore orig foreground/background
  805. CLS
  806. LOCATE , , 1                     ' make text cursor visible
  807. END
  808.  
  809.  
  810. _____________________________
  811. Some notes on the above code:
  812. 1)  LANGWIN.BI also contains the definitions found in QB.BI, so you won't need 
  813.     a separate "include" for the QB.BI file. LANGWIN.QLB also has the contents
  814.     of QB.QLB so you won't need that quick library either. For PDS users,
  815.     LANGWIN.BI covers QBX.BI and LANGWINP.QLB covers QBX.QLB. 
  816.  
  817. 2)  LANGWIN.BI contains all of the COMMON statements for LangWin's global 
  818.     variables. You should examine these variable names so that you don't 
  819.     mistakenly re-use the same name in your code (which will cause 
  820.     unpredictable results). 
  821.  
  822. 3)  LangWin will support both 80 and 40 columns, as well as 25, 43, and 50 
  823.     rows (as long as your hardware supports them). You can use the WIDTH 
  824.     command to set rows and columns; however, the WIDTH command MUST come 
  825.     before the call to LangWinInit (which tests the screen and sets global 
  826.     variables with current rows/columns on the screen). WARNING, using 43 or 
  827.     50 rows will increase the memory requirements for your programs and may
  828.     result in "out of memory" errors while developing.
  829.  
  830. 4)  PRIOR to calling LangWinInit, you MUST set MaxWindows to the maximum 
  831.     number of windows that can be opened on the screen at any one time. Keep 
  832.     this value a small as practical. It is used to DIM several arrays, and a 
  833.     large value can quickly use up all of the QB environment's free memory (in 
  834.     this case, you'll get an "out of memory" or perhaps "out of string space" 
  835.     message while developing). Use small values while developing in the QB 
  836.     environment. If your production code will need a larger value, set it just 
  837.     before creating your EXE file. If your program attempts to open more 
  838.     windows than defined by MaxWindows, the window will not open (you'll get a 
  839.     negative return code from the routine called to open the window). 
  840.    
  841. 5)  PRIOR to calling LangWinInit, you MUST set MaxButtons to the maximum 
  842.     number of buttons, check boxes, input fields, titles, and lines of
  843.     non-scrollable text lines that can be active on all visible windows. Like 
  844.     MaxWindows, this should be kept small during development and increased to a
  845.     practical value just before creating your EXE file. A large value of 
  846.     MaxButtons has less of a memory impact as MaxWindows. Thus, if you have a 
  847.     memory shortage while developing, reducing MaxWindows will buy back more 
  848.     storage. If your program exceeds MaxButtons, new objects will not be 
  849.     created (you'll get a non-zero return code from the routine called to 
  850.     create the object - if you don't test return codes, you'll notice that 
  851.     expected objects are missing from some windows). New with V2.1: non-
  852.     scrollable lines of text (created with ShowWinText) are saved in LangWin's
  853.     data structures (see section 5.0) so they can be re-displayed when a window 
  854.     is resized. Thus, if you are converting from a previous version of LangWin,
  855.     MaxButtons will have to be increased from it's previous value (by the 
  856.     number of lines of non-scrollable text and titles that can be active on all 
  857.     visible windows). Space in the data structures is used dynamically. As 
  858.     windows are opened and objects created, space is used. As windows are 
  859.     closed, space occupied by objects is freed. So, MaxButtons needs only to be
  860.     large enough to store the maximum number of objects, titles, and static 
  861.     text lines that would be visible on all windows open at any one time (this
  862.     includes all windows opened statically BEFORE the WinEvent loop, AND 
  863.     windows opened dynamically WITHIN the WinEvent loop in response to user 
  864.     actions). 
  865.  
  866. 6)  PRIOR to calling LangWinInit, you MUST set MaxTextLines (new with V2.0) to 
  867.     the maximum number of scrollable text lines in any window. When you open a
  868.     window to contain scrollable text (OpenScrollWindow), one of the parameters 
  869.     passed is a string array containing your scrollable text. LBOUND of this 
  870.     array MUST be 1; otherwise, OpenScrollWindow will fail with a run-time 
  871.     error. If the string array with your scrollable text is built dynamically
  872.     at run-time, then you must test to determine if the size exceeds 
  873.     MaxTextLines. If this conditions occurs, then OpenScrollWindow will only
  874.     display the first MaxTextLines of text. Your program will have to take
  875.     appropriate action to insure that the user will get to see all lines of 
  876.     text (e.g., give the user the option to see more and if chosen, delete
  877.     the first MaxTextLines of text, loop, and open a new window with 
  878.     scrollable text. Continue until all text has been seen). The contents of 
  879.     the string array passed to OpenScrollWindow is moved into a global array 
  880.     called SaveText(i,j) where UBOUND(SaveText,2)=MaxTextLines. Upon returning
  881.     from OpenScrollWindow, you can ERASE the string array (since the scrollable
  882.     text will have been saved in SaveText). This will help conserve memory.
  883.     Of course, if UBOUND(Text$) > MaxTextLines, then you must insure that the
  884.     user sees all of the Text$ array before you ERASE it.
  885.  
  886. 7)  PRIOR to calling LangWinInit, you MUST set MaxTextWins (new with V2.0) to 
  887.     the maximum number of simultaneous windows that can have scrollable text. 
  888.     All scrollable text is saved in SaveText(i,j) where UBOUND(SaveText,1) is
  889.     MaxTextWins. The value MUST be less than MaxWindows and (to conserve
  890.     memory) should be as low as possible.
  891.  
  892. 8)  LangWinInit sets constants, initializes all global variables, DIMs all 
  893.     arrays, and initializes and displays the mouse (if it exists). The 
  894.     constants TRUE (-1) and FALSE (0) are defined in LangWinInit and can be 
  895.     referenced in your code as needed. 
  896.  
  897. 9)  The global variable HaveMouse is set by LangWinInit and can be tested in 
  898.     your program to determine if a mouse exists. HaveMouse is set to TRUE if a 
  899.     mouse exists; else, it is set to FALSE. 
  900.  
  901. 10) Before writing anything to the screen, you must hide the mouse pointer (if 
  902.     a mouse exists). When a mouse pointer is on the screen, and a character is 
  903.     written to the same position, the character will not be displayed 
  904.     correctly. If a mouse exists, hide the pointer, write to screen, and then 
  905.     show the pointer. This technique is used when writing "wallpaper" on the 
  906.     screen. 
  907.  
  908. 11) While not necessary for windows, placing "wallpaper" on the screen for 
  909.     background provides a nice contrast. ASCII characters 176, 177, or 178 can 
  910.     be used for a nice effect. 
  911.    
  912. 12) Throughout ALL of your code, you MUST use the SetColor routine instead of 
  913.     the COLOR command to change color attributes. The parameters are the same 
  914.     (foreground and background attributes) as the COLOR command. LangWin uses 
  915.     BIOS interrupt 10h, function 10h, sub-function 03h to disable blinking 
  916.     colors. This allows 16 attribute numbers for window (background) colors 
  917.     (rather than just 8). However, with blinking disabled, foreground and 
  918.     background attribute numbers MUST be translated before calling BASIC's 
  919.     COLOR command. SetColor does this translation and issues the COLOR command 
  920.     with the proper values. If BASIC's COLOR command is called without this 
  921.     translation, you will get unexpected colors. 
  922.  
  923. 13) You MUST use the SCREEN 0 command BEFORE calling LangWinInit (V2.3). You 
  924.     can use any video page supported by your system. LangWinInit saves the 
  925.     video page you select in a global variable which is used by other routines
  926.     to read/write data in the video buffer. Thus, once you select a video page
  927.     in the initial SCREEN command (which must be BEFORE the call to 
  928.     LangWinInit), you should not change the video page in a subsequent
  929.     call to SCREEN. In general, there's no need to have another call to SCREEN.
  930.     One exception: for functions not associated with LangWin, you could use
  931.     SCREEN to change to a new page, display information on the screen, then
  932.     use SCREEN to change back to the original page number used in the
  933.     initial SCREEN command. For example, you could use LangWin to display
  934.     a scrollable list of filenames in one page. When a file name is clicked,
  935.     you could use SCREEN to change pages, SHELL to DOS and call a viewer to
  936.     display the selected file. Upon return from the SHELL, use SCREEN to
  937.     change back to the original page (containing the screooable list). In this 
  938.     case, be sure to test for a mouse and hide it before SHELLing and restore
  939.     it afterwards.
  940.  
  941. 14) I used the CLEAR command to initialize the stack at 9000 bytes. To save
  942.     memory and improve performance, LangWin is not compiled with the run-time 
  943.     debug option. Thus, you won't get an explicit warning if you exceed the 
  944.     stack space. Instead, you will get "strange" errors. In one case, the 
  945.     errors did not show up while developing in the QB environment. However, 
  946.     when testing with compiled code, strange things began to happen when the
  947.     compiled program terminated. Characters no longer appeared on the screen,
  948.     my machine locked up, or re-booted itself. If you suspect that you may be
  949.     exceeding the stack space (usually caused by many recursive calls to 
  950.     subroutines/functions, or just many subroutines/functions with many
  951.     parameters), print the value of FRE(-2) dynamically in your program
  952.     to determine stack space capacity and increase as necessary.
  953.     If FRE(-2) shows plenty of stack space free, you can reduce the size of
  954.     the stack or even omit the CLEAR command entirely.
  955.  
  956. 3.2 Some Simple Windows
  957. -----------------------
  958. Now, let's get on with creating some windows. LangWin requires a technique 
  959. called event-driven programming. (For those with Version 1.x of LangWin, the 
  960. event loop technique has been changed as of V2.0; you'll need to change your 
  961. program's logic). 
  962.  
  963. In general, for event-driven programming you must write code segments to handle 
  964. every possible event in every possible window, whether or not the window has 
  965. been opened yet (i.e., you must not only consider static windows that you open 
  966. when the program initializes, such as a main menu, but also any dynamic window 
  967. that will be opened "on the fly" based upon what object the user clicks, such 
  968. as an error window or sub-menu window). An event is defined as any 
  969. button/icon/text click. Your program consists of one main loop (new with V2.0; 
  970. previous versions required other loops), where you first call a special LangWin 
  971. routine (WinEvent) that will process all events. When an event occurs, the 
  972. special routine will return control to your program which must then determine 
  973. the exact window and event that occured, and execute a code segment dedicated 
  974. to handling that combination of window/event. In event-driven programming, the 
  975. event "drives" the code segment dedicated to processing that event. Your 
  976. program essentailly waits for an event (i.e., waits for control to be returned 
  977. from WinEvent), drives the corresponding code, and continues looping (until 
  978. some event occurs that signals termination). 
  979.  
  980. A high level view of your program's logic would be:
  981.  
  982.      open static window(s); save window numbers in unique variables
  983.      create buttons, input fields, click boxes as needed; save handles in
  984.                unique variables
  985.  
  986.      do while any window is open
  987.          wait for an event to occur in any window (call WinEvent)
  988.          determine which window had focus
  989.          determine which event occurred in the window that had focus
  990.          process the window/event combination (could open dynamic windows) 
  991.      loop
  992.  
  993.  
  994. As you can see, once static window(s) have been opened, you will loop: waiting 
  995. for an event, processing the event, and continuing the wait/process cycle as 
  996. long as any window remains open. Each possible window/event combination will 
  997. have a separate code segment dedicated to processing that event. Among the 
  998. actions that could be taken within the code segment, a dynamic window with its 
  999. own objects (buttons, click boxes, input fields, etc.) could be opened. If this 
  1000. is done, then your program would also need a code segment to handle events in 
  1001. this (and all other possible) dynamic window(s). 
  1002.  
  1003. The LangWin routines needed to accomplish the above tasks are:
  1004. (these are just a sub-set of all routines in LangWin, see WINHELP.BAS
  1005. for complete documentation):
  1006.      BlankWin           -  opens a plain window; returns window number
  1007.      OpenScrollWindow   -  opens a window with scrollable text; returns number
  1008.      MakePushButton     -  creates a push button; returns its handle value
  1009.      MakeCheckBox       -  creates a check box; returns its handle value
  1010.      MakeInputField     -  creates an input field; returns its handle value
  1011.      WinEvent           -  processes all GUI activity within all open windows.
  1012.                            returns a value that identifies the number of
  1013.                            the window with focus (see Section 5.7 for more 
  1014.                            information on window numbers), and returns a 
  1015.                            parameter that defines the event that occurred 
  1016.                            (1=close; 2=text line selected; 3=button selected).
  1017.      CloseWindow        -  close the current window
  1018.      ShowWinText        -  places static (non-scrollable) text into current
  1019.                            window 
  1020.  
  1021.  
  1022. See Section 6.7 for additional details on event-driven programming techniques.
  1023.  
  1024.  
  1025. -----------------------
  1026. 4.0 USING LANGWIN'S GUI
  1027. -----------------------
  1028. Before describing LangWin's data structures and providing more advanced 
  1029. techniques for doing windows, a brief description of how to use the GUI 
  1030. created by LangWin will be presented.
  1031.  
  1032. Windows created by LangWin have the following standard GUI features:
  1033.  
  1034. 4.1 Close Icon
  1035. --------------
  1036. The upper left corner of each window can optionally have a close icon (this is 
  1037. determined by the  CloseIcon parameter in the BlankWin and OpenScrollWindow 
  1038. routines, see WINHELP.BAS). Double click on this icon and WinEvent will return 
  1039. an action code of 1 to your program. Regardless of whether a close icon is 
  1040. displayed, hitting the ESC key will return an action code of 1 to your program 
  1041. (if you are in an input field, ESC will exit the input field; hit ESC again if 
  1042. you want to close the window. See Input Fields below for details). You can 
  1043. choose to ignore the close event in your program, and instead require a 
  1044. specific button click to effect the window being closed. 
  1045.  
  1046. 4.2 Moving, Resizing, and Minimizing the Active Window
  1047. ------------------------------------------------------
  1048.  
  1049. 4.2.1 Moving
  1050. ------------
  1051. Windows can be moved to any position on the screen (as long as the window is 
  1052. marked as movable). Using the left mouse button, click and hold the close icon 
  1053. (if there is no close icon, click and hold the upper left corner of the 
  1054. window). After a moment (in this case, a "moment" equals approximately 2/9 
  1055. second), the mouse pointer will change to a pair of "corner pointers": one in 
  1056. the upper left corner of the window and one in the lower right. (If the mouse 
  1057. pointer does not turn into "corner pointers", then the window is not movable - 
  1058. see description of OpenScrollWindow and BlankWin for details on how to mark a 
  1059. window as unmovable). While holding the mouse button down, drag the pair of 
  1060. "corner pointers" to a new position and release the mouse button. Don't forget 
  1061. that if the window has a shadow, the new position must have room for the 
  1062. shadow (the "corner pointers" only show the extent of the window, not it's 
  1063. shadow which takes two columns on the right and one row below the window). 
  1064. When moving a window, the mouse cursor is limited such that you won't be able 
  1065. to move the window off of the screen (if the window has a shadow, the cursor 
  1066. limit will leave room for it). 
  1067.  
  1068. See the WinColor parameter in BlankWin and OpenScrollWindow for details on how 
  1069. to mark a window as unmovable. See the BorderColor parameter (in the same two
  1070. routines) for details on making a window shadowless. 
  1071.  
  1072. 4.2.2 Resizing
  1073. --------------
  1074. Using the RIGHT mouse button, click and hold any of the window's corners. After 
  1075. a moment (2/9 sec) the mouse pointer will change into a "corner pointer". (If 
  1076. the mouse pointer does not change, then the window is not resizable - see 
  1077. OpenScrollWindow and BlankWindow for details on how to mark a window as not 
  1078. resizable). Drag the corner pointer to a new position and release. The window 
  1079. will be resized appropriately. LangWin imposes certain limits when shrinking 
  1080. windows. If the window has a scrollable text area, the window cannot be made so 
  1081. small that the text area would disappear (the smallest that the text area can 
  1082. be is one character). In this case, the resulting size of the window containing 
  1083. scrollable text will depend upon the size of the borders (within the window) 
  1084. around the scrollable text area (which can be anywhere within a window - see 
  1085. OpenScrollWindow). If the window does not have scrollable text, then the 
  1086. smallest it can be is three characters by three characters (including the 
  1087. characters that make up the border). 
  1088.  
  1089. When a window is expanded or contracted, the text area (if present) and all 
  1090. buttons, input fields, check boxes, titles, and plain text (non-scrollable) 
  1091. will be moved proportionally. When a window is contracted, these objects will 
  1092. be closer together and may appear "squished". If the window is made small 
  1093. enough, some of these objects will DISAPPEAR (because they will no longer be in 
  1094. the visible area of the window). Making the window larger will cause these 
  1095. objects to re-appear. However, some objects WILL disappear altogether when a 
  1096. window is resized. These include horizontal lines (see MakeHorizLine), vertical 
  1097. lines (MakeVertLine), and boxes (MakeBox) - also see Section 6.1. If this 
  1098. presents a problem (i.e., you NEED to have these objects in your window, and 
  1099. having them disappear when your end user resizes the window is not acceptable, 
  1100. then mark the window as not resizable when it's opened). 
  1101.  
  1102. See the BorderColor parameter in BlankWin and OpenScrollWindow for details on 
  1103. how to mark a window as not sizable.
  1104.  
  1105. HINT: when a window is resized, it's objects are redrawn (at new positions) in 
  1106. the same order in which they were created. If the window gets too small, some 
  1107. adjacent objects (in the original window) may be redrawn in the same space (in 
  1108. the smaller window) and overlay one another. In this case, the last object 
  1109. redrawn will appear "on top" of others (and may even completely hide others 
  1110. that are "beneath" it). Thus, for adjacent objects in the original window, the 
  1111. object want to appear "on top" of others (when a window is made smaller) should 
  1112. be defined last. For example, as the window is made smaller, non-scrollable 
  1113. text (see ShowWinText) in the window's second row and the window's title (see 
  1114. ShowTitle) in first row might both be placed on the first row of the window. If 
  1115. you want the title to appear "on top" of the non-scrollable text in this case, 
  1116. then place the CALL ShowTitle after all CALL ShowWinText (for text in the given 
  1117. window). 
  1118.  
  1119. HINT: a window with scrollable text can be opened without a scroll bar (for 
  1120. example, when items in a scrollable list are used to select sub-menus, and you 
  1121. know that the entire list will fit into the original window, then you might 
  1122. choose to specify no scroll bar for the window). If you shrink this window to 
  1123. the point where all of the scrollable text will not fit, then some scrollable 
  1124. text (i.e., your menu items) will not be displayed. In this case, a scroll bar 
  1125. will NOT be automatically included when the window is shrunk (because the 
  1126. original specification to omit a scroll bar will take precedence). If you must 
  1127. open a window with scrollable text and specify that that it not have a scroll 
  1128. bar, then I'd recommend making the original window not sizable (see BorderColor 
  1129. parameter in OpenScrollWindow routine). 
  1130.  
  1131. HINT: if a window is marked as unmovable, it cannot be resized (regardless of 
  1132. the state of the resize flag).
  1133.  
  1134. 4.2.3 Minimizing
  1135. ----------------
  1136. Place the mouse cursor ANYWHERE in the window, then click and hold BOTH left 
  1137. and right buttons. After a moment (2/9 sec), the window will be contracted to 
  1138. its minimal size (by simulating the process of dragging the lower right corner 
  1139. to the upper left as far as possible - see previous section for a discussion on 
  1140. minimal size). Repeating this process on a window that has been minimized will 
  1141. (in most cases) expand the window to its original size (by simulating the the 
  1142. process of dragging the lower right corner back to the original position). 
  1143.  
  1144. Both resized and minimized windows can be moved (left click on upper left 
  1145. corner and drag). If a minimized window is moved closer to the bottom row or 
  1146. right edge of the screen, then clicking with both buttons to expand back to 
  1147. original size would result in the window extending beyond the screen's 
  1148. boundaries. In this case, the window will be expanded as large as possible (but 
  1149. may indeed be smaller than its original dimensions). 
  1150.  
  1151. See the BorderColor parameter in BlankWin and OpenScrollWindow for details on 
  1152. how to mark a window as not sizable (which means it cannot be minimized). 
  1153.  
  1154. HINT: if the window's size has been changed (by dragging a corner with the 
  1155. right button), and you want to return the window to its original size, first 
  1156. click with both buttons to minimize, then click with both buttons again to 
  1157. expand back to original size. Of course, you could also drag a corner with the 
  1158. right button to resize back to original dimensions (unless you don't remember 
  1159. what original window looked like). 
  1160.  
  1161. HINT: here's a technique I've found for clicking both buttons to minimize. 
  1162. Place the mouse pointer on the window to be minimized (but not on a corner). 
  1163. Click the right button, then click the left button. The point is that the right 
  1164. button should be clicked first (so that just in case you happen to be on a 
  1165. button or some other object, no action will be taken), then the left button is 
  1166. clicked. You don't have to actually click both simultaneously; they both just 
  1167. have to be down. I found that trying to click both simultaneously sometimes 
  1168. actually results in the left button being clicked first. In this case, if the 
  1169. pointer happens to be on and object, that object will be selected. Yes, I could 
  1170. have used another icon on the window's border to implement minimizing; I just 
  1171. liked the idea of being to minimize with the mouse cursor anywhere on the 
  1172. window in question. My apologies to those who dislike the right mouse button 
  1173. (but as long as it's there, I thought I'd use it). 
  1174.  
  1175. HINT: if a window is marked as unmovable, it cannot be resized (regardless of 
  1176. the state of the resize flag), and thus it cannot be minimized.
  1177.  
  1178.  
  1179. 4.3 Focus 
  1180. ---------
  1181. Before discussing buttons, check boxes, input fields, and scrollable text, the 
  1182. concept of focus must be reviewed. Focus has taken on additional meaning with 
  1183. V2.0 and later. A window can have focus (i.e., it's the current window), and an 
  1184. object within the current window can have focus. 
  1185.  
  1186. When WinEvent returns control to your program, the value of the WinEvent 
  1187. function corresponds to the number of the window that had focus when the event 
  1188. occurred. The value of WinEvent's parameter is a code for the type of action 
  1189. that occurred in the window with focus. You will need to determine which line 
  1190. of text or button caused that event (i.e., had focus when the event occurred). 
  1191. Clicking anywhere on a window gives it focus. Clicking on a window's object 
  1192. (i.e., button, check box, input field, or scrollable text) gives the owning 
  1193. window and the corresponding object focus (input fields will display a cursor 
  1194. when they have focus, other objects will be displayed in reverse video). Note 
  1195. that if scrollable text exists, one line ALWAYS has focus. If buttons, check 
  1196. boxes, and input fields exist, one of them usually has focus (but it is 
  1197. possible for none of the buttons, check boxes, or input fields to have focus, 
  1198. see Changing Focus below). Thus, it is possible for BOTH a line of text AND a 
  1199. button to have focus when WinEvent returns to your program. See Section 6.6 for 
  1200. details on how to distinguish between the line of text with focus and the 
  1201. button with focus when WinEvent returns control to your program. 
  1202.  
  1203.  
  1204. 4.4 Changing Focus
  1205. ------------------
  1206. With LangWin 2.0, you can mouse to any visible window and select an object. 
  1207. Thus, you'll need to understand the difference between the current window with 
  1208. focus and the current object in a window with focus. There are actually two 
  1209. kinds of focus: "window focus" - the current window; and "object focus" - the 
  1210. current object in a window. Clicking on a window gives it "window focus". 
  1211. Clicking on an object in a window gives "window focus" to the selected window 
  1212. and "object focus" to the selected object. The following two sub-sections will 
  1213. help to clear up these concepts. 
  1214.  
  1215. 4.4.1 Window Focus
  1216. ------------------
  1217. Only one window can have focus. If your program creates a window (with BlankWin 
  1218. or OpenScrollWindow), then it has window focus. Until that focus is changed, 
  1219. any subsequent objects created with "make" routines will be associated with 
  1220. that window. Window focus can be changed by clicking anywhere on any visible 
  1221. window. That window will be moved to the "top" of the stack of overlapping 
  1222. windows and given focus (in addition, if an object in that window was clicked, 
  1223. it will be given object focus - see next section). Pressing CTRL and PgUp will 
  1224. also change the window in focus (the "bottom" window on the screen is moved to 
  1225. the "top" and given focus). Repeated use of CTRL-PgUp will cycle through all 
  1226. visible windows. If the windows displayed are overlapping, you'll easily be 
  1227. able to tell which window has focus (it will appear on "top" of the stack). If 
  1228. the windows do not overlap, there won't be a visible difference between the 
  1229. window with focus and all others. If you use the keyboard to control the GUI 
  1230. (see Section 4.10), then keyboard commands (such as TAB, ENTER, etc) take 
  1231. effect only in the window with focus. 
  1232.  
  1233.  
  1234. 4.4.2 Object Focus
  1235. ------------------
  1236. Every object in a window can also be given focus. Typically, just clicking on 
  1237. the object will give it focus and it will be displayed in reverse video (when 
  1238. input fields have focus, a text cursor appears in the field). While it is 
  1239. possible for no button or check box to have focus, if there is scrollable text 
  1240. in the window, then one line will ALWAYS have focus (one exception: null lines 
  1241. in scrollable text can have focus, but they will be invisible and appear as if 
  1242. no scrollable text has focus). There are several ways to change focus. Clicking 
  1243. on any object will give it focus. If a line of scrollable text is clicked, then 
  1244. it is given focus (and focus is removed from any button or check box previously 
  1245. having focus). If a button, check box, or input field is clicked, then it 
  1246. obtains focus (and the text focus is unchanged). Thus, if both scrollable text 
  1247. and other objects exist in a window, there will always be one line of text with 
  1248. focus, and there may or may not also be another object with focus. 
  1249.  
  1250. In addition to clicking on an object to give it focus, the TAB and Shift-TAB 
  1251. keys can be used to change the focus of buttons, check boxes, or input fields 
  1252. in the current window (text focus is not affected by TAB). Hitting TAB will 
  1253. move focus to the next button, check box, or input field (if scrollable text 
  1254. exists, one line ALWAYS has focus, and this focus remains unchanged by the TAB 
  1255. keys. Text focus is only changed by mouse or scrolling). Shift-TAB will move 
  1256. the focus to the previous button, check box, or input field. After cycling 
  1257. through all buttons, check boxes, and input fields, the focus will disappear 
  1258. (except for the line of scrollable text with focus). Hitting TAB or Shift-TAB 
  1259. will cause the focus to reappear on the next/previous button, check box, or 
  1260. input field. 
  1261.  
  1262. Unless an input field is being actively edited (see Input Field), the 
  1263. left/right arrow keys will function like TAB/Shift-TAB for changing focus. The 
  1264. up/down arrows change text focus, scrolling the list as appropriate. 
  1265.  
  1266. If scrollable text does not exist, then the up/down arrows will also function 
  1267. like TAB/Shift-TAB for changing focus. 
  1268.  
  1269. When you hit ENTER, the object with focus is selected (just as if it were 
  1270. clicked with a mouse). If BOTH a line of scrollable text AND an object
  1271. (i.e., push button or check box) has focus, then an action code of 3 will 
  1272. be returned from WinEvent (i.e., the object takes precedence). In this case,
  1273. your code can check WinParms(CurWinPtr,16) to get the handle of the button
  1274. pushed and WinParms(CurWinPtr,18) and WinParms(CurWinPtr,15) to get indices
  1275. in SaveText that correspond to the line of text currently in focus (see Section 
  1276. 5.8).
  1277.  
  1278.  
  1279. 4.5 Scrolling Text
  1280. ------------------
  1281. The right side of each window can optionally show a scroll bar, slider, and 
  1282. up/down arrows. These will not be present if a plain window was opened 
  1283. (BlankWin), or if you specifically open a window with scrollable text, but 
  1284. specify no scroll bar (see BorderType parameter in OpenScrollWindow). If the 
  1285. scrollable text array will completely fit into the defined text area of the 
  1286. window (i.e., nothing to scroll), then the slider will not be displayed (scroll 
  1287. bar and arrows will still be visible). If a scroll bar exists, then WinEvent 
  1288. will handle all scrolling for you. Scrolling will change the text line that has 
  1289. focus (shown in reverse video). The user can click on the up/down arrows to 
  1290. scroll one line at a time. Click on the scroll bar (not the slider) and the 
  1291. text will page up/down (if the click was below the slider, page down; above the 
  1292. slider, page up). Drag the slider up/down, and the text will scroll to the 
  1293. correct relative new position of the slider when the mouse button is released 
  1294. (usual GUI stuff). 
  1295.  
  1296. The keyboard can also be used to scroll. Up/down arrows for single lines. 
  1297. Home/End keys for start/end of text, and PgUp/PgDown for paging. 
  1298.  
  1299. If the scrollable text has null lines, when one of these is given focus 
  1300. (clicking, arrows, scrolling, etc.), it will still appear as null (i.e., 
  1301. invisible). This will make the scrollable text focus seem to disappear when 
  1302. selecting a null line. This could be confusing to the end user, and unless you 
  1303. have a specific use for it, I'd recommend that your scrollable text not include 
  1304. null lines. When OpenScrollWindow creates a list of scrollable text, all null 
  1305. entries that exist at the end of the text array are eliminated (null lines 
  1306. within the text array are not eliminated). 
  1307.  
  1308.  
  1309.  
  1310. 4.6 Selecting Scrollable Text
  1311. -----------------------------
  1312. The OpenScrollWindow takes a parameter that defines an array of scrollable 
  1313. text. This text is displayed in the window, and as previously described, can 
  1314. be scrolled up or down. Single clicking on a line of text will give it focus.
  1315. Double-clicking on a line of text will give it focus, AND will return control
  1316. from WinEvent with an action code of 2 (value of the WinEvent function will be 
  1317. the window's number where the text was clicked). 
  1318.  
  1319.  
  1320. 4.7 Push Buttons
  1321. ----------------
  1322. The MakePushButton routine is used to create push buttons in the current window 
  1323. (it returns a unique handle number associated with the button created). These 
  1324. buttons can optionally have drop shadows. Clicking on any push button will give 
  1325. it focus, AND will return control from WinEvent with an action code of 3 (value 
  1326. of the WinEvent function will be the window's number where the button was 
  1327. clicked). Depending upon the logic of your program, you can deactivate/activate 
  1328. individual push buttons. Deactivating the button will cause its text to clear 
  1329. (the button itself, and any shadow, is still visible, just its text is clear). 
  1330. Any subsequent clicks on a deactivated button will NOT produce any events. 
  1331. Activating the button will cause its text to be visible and click events to be 
  1332. recognizes. A button can be used to open a child window. If you do not want the 
  1333. end user to be able to click the button again while the child window remains 
  1334. open, then use the deactivate function. When the child window is closed, 
  1335. activate the button. 
  1336.  
  1337.  
  1338. 4.8 Check Boxes
  1339. ---------------
  1340. The MakeCheckBox routine is used to create check boxes in the current window 
  1341. boxes are toggle switches used to select (un-select) user defined options. 
  1342. Clicking on a check box will give it focus and change its state (from up to 
  1343. down, or down to up). There are no check box actions/events that would cause 
  1344. WinEvent to return control to your program; thus, there are no WinEvent action 
  1345. codes associated with check boxes. However, after control is returned to your 
  1346. program (for some other event), you can examine the state of all check boxes in 
  1347. the current window. WinEvent's return value will tell you the current window, 
  1348. and the code you write to handle that window's events should test each check 
  1349. box created in the window (by referencing the specific variables you used to 
  1350. save the handles of all boxes in that window). Depending upon the state of the 
  1351. check boxes in the current window, your code can take any necessary action (see 
  1352. DATA STRUCTURES and ADVANCED WINDOWS below). 
  1353.  
  1354.  
  1355. 4.9 Input Fields
  1356. ----------------
  1357. The MakeInputField routine is used to create input fields in the current window 
  1358. (it returns a unique handle number associated with the field created).  An 
  1359. input field is an editable area that can be used for data entry. Tabbing to, or 
  1360. clicking on, an input field will give it focus (cursor will be visible) and 
  1361. make it available for data entry and/or editing. Input fields can be re-
  1362. selected at any time to make changes/corrections as necessary. There are no 
  1363. actions/events from an input field that would cause WinEvent to return control 
  1364. to your program; thus, there are no WinEvent return codes associated with 
  1365. input fields. However, after control is returned to your program (for some 
  1366. other event), you can examine the contents of all input fields in the current 
  1367. window to see if they have been updated. WinEvent's return value will tell you 
  1368. the current window, and the code you write to process that window's events 
  1369. could test the current contents of each input field created in the window (by 
  1370. referencing data associated with each input field's unique handle). Your code 
  1371. would have to "remember" the previous contents to determine if the input field 
  1372. had been changed. Depending upon the current contents of the input fields in 
  1373. the current window, your code would take any necessary action (see DATA 
  1374. STRUCTURES and ADVANCED WINDOWS below). The following keys are available while 
  1375. in an input field: 
  1376.  
  1377.         ESC         - exit input field (useful if you have several input 
  1378.                       fields, but want your mouse pointer back immediately)
  1379.                       current window retains focus
  1380.  
  1381.         Ctrl-PgUp   - exit the input field (next WINDOW given focus)
  1382.                       (new with V2.0)
  1383.  
  1384.         ENTER       - exit input field (next object given focus) 
  1385.         TAB         - exit input field (next object given focus)
  1386.         DOWN Arrow  - exit input field (next object given focus)
  1387.         Shift-TAB   - exit input field (previous object given focus)
  1388.         UP Arrow    - exit input field (previous object given focus)
  1389.                       (the above 5 keys are useful if you have several input
  1390.                       fields and want to go to next/previous field immediately
  1391.                       after completing the current field - data entry)
  1392.  
  1393.         Ctrl-c      - clear entire contents of the input field
  1394.         Ctrl-y      - clear entire contents of the input field
  1395.  
  1396.         Ctrl-END    - clear input field from cursor to end
  1397.  
  1398.         INSERT, BACKSPACE, LEFT/RIGHT Arrows, DELETE, HOME, END 
  1399.         (the above keys should be self explanatory)
  1400.  
  1401. While in data entry mode (within an input field), the mouse remains active. In 
  1402. addition to the Arrow keys, you can use the mouse to position the text cusror. 
  1403. In addition to the ESC key, you can use the mouse to exit an input field (just 
  1404. click anywhere outside the input field). 
  1405.  
  1406. An input field can easily be used for password entry. When defining the input 
  1407. field (via MakeInputField), use a negative value for its length (new with 
  1408. V2.2). This will force all text entered into the field to be displayed with 
  1409. the * character. Another technique (available in previous releases) for 
  1410. entering passwords would be to use the same value for both the foreground and 
  1411. background colors of the input field. In this case, nothing will be displayed 
  1412. when text is entered. For both techniques, the actual text entered (i.e., the 
  1413. password) is saved in ButtonsText(handle) - just as for any other input field - 
  1414. and could be used to validate the password. See DATA STRUCTURES for a 
  1415. description of the contents of ButtonsText. 
  1416.  
  1417.  
  1418. 4.10 No mouse
  1419. -------------
  1420. For those without a mouse (or those writing code that might run on systems 
  1421. without a mouse), LangWin's GUI functions can be selected via the keyboard. The 
  1422. Changing Focus Section (above) already described how to use the keyboard to 
  1423. change focus. To select the current object with focus, just hit ENTER. 
  1424.  
  1425. If a push button has focus, hitting ENTER will return control from WinEvent 
  1426. with a value of 3. (Note that even though a line of scrollable text ALWAYS has 
  1427. text focus, if a button has focus, hitting ENTER will return from WinEvent with 
  1428. a code of 3. In this case, if you need to know which line of text also had 
  1429. focus, then this can be done - see DATA STRUCTURES and ADVANCED WINDOWS for 
  1430. additional details). 
  1431.  
  1432. If a check box has focus, hitting ENTER will toggle the check box, but an event 
  1433. code will NOT be generated and control will remain within WinEvent. 
  1434.  
  1435. If an input field has focus, hitting ENTER will exit the input field and move 
  1436. focus to the next object (in current window). An event code will NOT be 
  1437. generated and control will remain within WinEvent. 
  1438.  
  1439. If ONLY a line of scrollable text has focus (i.e., no button, check box, or
  1440. input field has focus), hitting ENTER will return control from WinEvent with am 
  1441. action code of 2. By hitting TAB, you will cycle the focus through all buttons, 
  1442. check boxes, and input fields, and eventually get to a state where the ONLY 
  1443. object with focus is a line of scrollable text (if no scrollable text exists, 
  1444. then focus disappears). 
  1445.  
  1446.  
  1447. ----------------------------------------
  1448. 5.0 DATA STRUCTURES AND GLOBAL VARIABLES
  1449. ----------------------------------------
  1450. The following subsections describe LangWin's data structures and global 
  1451. variables (some of which have been added/changed with LangWin 2.0). You will 
  1452. need this information for the advanced window techniques presented in the  
  1453. Section 6.0. The global variables that are user definable could either be hard 
  1454. coded in your program or read from an INI file (so your end user can change 
  1455. them to meet system requirements and/or constraints). 
  1456.  
  1457.  
  1458. 5.1 MaxWindows
  1459. --------------
  1460. This global variable defines the maximum number of open windows that can appear 
  1461. on the screen at one time. If you try to open more windows than MaxWindows, the 
  1462. BlankWin or OpenScrollWindow routines will fail and return an error code. 
  1463. MaxWindows MUST be defined by you PRIOR to calling LangWinInit and SHOULD NOT 
  1464. BE CHANGED (see Section 3.1 for additional details). 
  1465.  
  1466. 5.2 MaxButtons
  1467. --------------
  1468. This global variable defines the maximum number of push buttons, check boxes, 
  1469. input fields, window titles, and lines of non-scrollable text that can be 
  1470. created on all possible open windows. If you attempt to create more objects, 
  1471. the corresponding "make" routine will return an error code. MaxButtons MUST be 
  1472. defined by you PRIOR to calling LangWinInit and SHOULD NOT BE CHANGED (see 
  1473. Section 3.1 for additional details). 
  1474.  
  1475. New with V2.1: non-scrollable lines of text (created with ShowWinText) are 
  1476. saved in LangWin's data structures (see section 5.0) so they can be re-
  1477. displayed when a window is resized. Thus, if you are converting from a previous 
  1478. version of LangWin, MaxButtons will have to be increased from it's previous 
  1479. value (by the number of lines of non-scrollable text and titles that can be 
  1480. active on all visible windows). Space in the data structures is used 
  1481. dynamically. As windows are opened and objects created, space is used. As 
  1482. windows are closed, space occupied by objects is freed. So, MaxButtons needs 
  1483. only to be large enough to store the maximum number of objects, titles, and 
  1484. static text lines that would be visible on all windows open at any one time
  1485. (this includes all windows opened statically BEFORE the WinEvent loop, AND
  1486. windows opened dynamically WITHIN the WinEvent loop in response to user 
  1487. actions).                       
  1488.  
  1489.                        
  1490. 5.3 MaxTextLines
  1491. ----------------
  1492. This global variable defines the largest number of scrollable text lines that 
  1493. can appear in any window. If your program will open two windows, one with 25 
  1494. lines of scrollable text and another with 50 lines, then (in this case) 
  1495. MaxTextLines would have to be set to 50. MaxTextLines MUST be defined by you 
  1496. PRIOR to calling LangWinInit and SHOULD NOT BE CHANGED (see Section 3.1 for 
  1497. additional details). New with 2.0. 
  1498.  
  1499. If the number of scrollable text lines to be displayed in a window is not 
  1500. known during development, but will be determined dynamically at run-time, then 
  1501. you must take a best guess at a reasonable value for MaxTextLines. 
  1502. OpenScrollWindow will compare the UBOUND of the string array passed with 
  1503. MaxTextLines. If UBOUND(Text$) > MaxTextLines, then OpenScrollWindow will
  1504. only display the first MaxTextLines of the array. In this case, the last
  1505. line displayed will be set to the string:     "(Incomplete List)" 
  1506. so your user will be aware that some data is missing. Your program should 
  1507. detect this condition (by comparing UBOUND(Text$) to MaxTextLines) and take
  1508. appropriate action. For example, your could offer the user an option to
  1509. see the missing text, and if selected, delete the first MaxTextLines from the 
  1510. Text$ array, loop, and open a new scrollable text window. Continue until
  1511. all text has been displayed. Alternatively, you could just split the
  1512. original Text$ array into smaller arrays (size <= MaxTextLines) and open
  1513. a scrollable window for each. I'll leave the details to you!
  1514.  
  1515. 5.4 MaxTextWins
  1516. ---------------
  1517. This global parameter defines the maximum number of windows that can be open 
  1518. with scrollable text. MaxTextWins MUST be <= MaxWindows (makes sense; can't 
  1519. have more text windows than windows of any kind, right!). MaxTextWins is 
  1520. used to dimension the global array SaveText which will hold all scrollable text 
  1521. in all open windows (see Section 5.8 for more details on SaveText array). 
  1522. MaxTextWins MUST be defined by you PRIOR to calling LangWinInit and SHOULD 
  1523. NOT BE CHANGED (see Section 3.1 for additional details on MaxTextWins). 
  1524. New with V2.0.
  1525.  
  1526. 5.5 AnyWinOpen
  1527. --------------
  1528. With LangWin 2.0, this global variable is created, defined, and changed by 
  1529. LangWin's routines. It will be TRUE when any window is open and FALSE when all 
  1530. windows have been closed (DO NOT CHANGE THIS VARIABLE). You can use it to 
  1531. control the exit from your loop that checks WinEvent as follows: 
  1532.  
  1533.         DO WHILE AnyWinOpen
  1534.            wnum=WinEvent(action)
  1535.            process the action in window # wnum
  1536.         LOOP
  1537.  
  1538.  
  1539.  
  1540. 5.6 CurWinPtr
  1541. -------------
  1542. When a window is opened (via BlankWin or OpenScrollWindow), its parameters are 
  1543. stored in an available "slot" of the WinParms array (see Section 5.9). The 
  1544. "slot" in WinParms is called the window's handle. The handle of the current 
  1545. window with focus can always be found in the global variable CurWinPtr. 
  1546. CurWinPtr is created, defined, and updated by LangWin's routines (DO NOT DEFINE 
  1547. OR CHANGE IT). 
  1548.  
  1549.  
  1550. 5.7 Window numbers vs window handles
  1551. ------------------------------------
  1552. With LangWin 2.0, when a window is opened (via BlankWin or OpenScrollWindow), 
  1553. it is given a unique window number (i.e., the value returned by the function 
  1554. used to open the window). The window number should be saved in a unique 
  1555. variable name. The window's parameters are stored in the WinParms array. The 
  1556. "slot" in WinParms where the window's data is saved is called its handle. 
  1557. Window numbers are unique; window handles are not unique. Window handles are 
  1558. re-used after a window is closed (i.e., the "slot" in WinParms will be re-used 
  1559. to hold a new window's parameters). 
  1560.  
  1561. The window's handle cannot be used to uniquely determine what to do when 
  1562. control returns from WinEvent (i.e., after an event occurred in a window). The 
  1563. window's number, however, is a unique sequential value which is never re-used. 
  1564. The number of the window where an event occurred must be used to uniquely 
  1565. determine how to process events in that window. For example, handle number 3 
  1566. might point to data for window number 6 at one point, and after that window is 
  1567. closed and another is opened, handle number 3 could then point to data for 
  1568. window number 7. If the window's handle (3) were used to select code to process 
  1569. the event, you would not know exactly what to do because either window 6 or 7 
  1570. could have caused the event. Using the window's number, however, will tell you 
  1571. exactly which window caused the action, and thus you can select the proper code 
  1572. to handle events for that window (each window will have a different set of code 
  1573. to handle its events, you'll also have to determine which event occurred in the 
  1574. given window). This is probably the only time you'll need the window's number 
  1575. (i.e., to select the proper code to handle a window's events). Within your code 
  1576. to process events for a window, use CurWinPtr to index the WinParms array
  1577. to get data for the event that occurred. CurWinPtr contains the handle of the 
  1578. current window with focus (which is the window that contained the event that 
  1579. caused control to be returned from WinEvent). Section 3.2 contains pseudo code 
  1580. that demonstrates this technique (called event-driven programming). WinNum is a 
  1581. cross reference array containing window numbers. WinNum(i) contains the window 
  1582. number that corresponds to handle i - see Section 5.14 for details on WinNum. 
  1583.  
  1584.  
  1585. 5.8 SaveText
  1586. ------------
  1587. This structure is DIMed as follows: 
  1588. SaveText(1 to MaxTextWins, 1 to MaxTextLines) AS STRING
  1589.  
  1590. It is used to hold all scrollable text in all currently open windows. The 
  1591. first dimension defines "slots" for the set of scrollable text in a given 
  1592. window. The second dimension defines specific lines of text in that window. 
  1593. OpenScrollWindow takes the string array passed with scrollable text and copies 
  1594. it into an open slot in SaveText. It saves the "slot" value in 
  1595. WinParms(CurWinPtr,18) - see Section 5.9 for details on WinParms(). 
  1596.  
  1597. Upon returning from WinEvent, if action=2 (i.e., text line selected), then 
  1598. SaveText(i,j) will be the line of text with focus; where: 
  1599. i=WinParms(CurWinPtr,18) and j=WinParms(CurWinPtr,15) 
  1600. SaveText is new with V2.0.
  1601.  
  1602.                                                          
  1603. 5.9 WinParms
  1604. ------------
  1605. This structure is DIMed as follows: WinParms(1 to MaxWindows, 1 to 19) The 
  1606. first dimension is called the window's "handle". This is the "slot" where data 
  1607. for a given window is saved when it's opened. CurWinPtr (see Section 5.6) 
  1608. always contains the handle of the window with focus. 
  1609.  
  1610. Each open window has the following 22 entries defined:
  1611.  
  1612.      1 --- starting row of window (relative to screen)
  1613.      2 --- starting column of window (relative to screen)
  1614.      3 --- ending row of window (relative to screen)
  1615.      4 --- ending column of window (relative to screen)
  1616.      5 --- color attribute of window's background
  1617.      6 --- color attribute of window's border
  1618.      7 --- border type: (neg value will prevent scroll bar from being used)
  1619.             1 = single line,  2 = double line
  1620.            -1 = single line, -2 = double line
  1621.      8 --- color attribute of foreground text in window
  1622.  *   9 --- index of scrollable text's array entry currently at top of win
  1623.     10 --- starting row of scrollable text area (relative to window)
  1624.     11 --- starting column of scrollable text area (relative to window)
  1625.     12 --- ending row of scrollable text area (relative to window)
  1626.     13 --- ending column of scrollable text area (relative to window)
  1627.  *  14 --- absolute screen row of scrollable text line that currently has focus
  1628.  *  15 --- 2nd index in SaveText array: text line with focus (-1 if no text)
  1629.  *  16 --- handle of button with current focus (-1 if no button has focus)
  1630.     17 --- last row of SaveText array with non-null value
  1631.     18 --- 1st index in SaveText: all of window's text (-1 if no text)
  1632.     19 --- mode of window (1=modeless; 2=modal; 3=immediate close; 4=wallpaper)
  1633.            (negative values imply window is shadowless)
  1634.     20 --- # rows in original window (used for resize)
  1635.     21 --- FLAGS
  1636.             01h - movable (1=movable; 0=unmovable)
  1637.             02h - sizable (1=sizable; 0=not sizable)
  1638.  *          04h - window minimized status (1=minimized; 0=not minimized).
  1639.     22 --- # columns in original window (used for resize)
  1640.  
  1641. Values marked with * are dynamic and will change as the active window is 
  1642. manipulated within the WinEvent function. All other values remain unchanged 
  1643. after window is opened (unless window is moved, in which case row/col values 
  1644. are translated based upon new location of window). If not used (i.e., no 
  1645. scrollable text, buttons, etc. in the window), then entries 9-22 are 
  1646. initialized to -1. 
  1647.  
  1648. Entries 17-21 were new with V2.0. 
  1649. Entries 20-22 were changed in V2.1.
  1650.  
  1651. Examples: If WinEvent returns an action code of 3 (signifying a button 
  1652. selection event), then WinParms(CurWinPtr,16) contains the handle of the button 
  1653. that was clicked. If you code; han=WinParms(CurWinPtr,16) in the routine that 
  1654. processes a button click, then ButtonsData(han,i) contain information on the 
  1655. corresponding button (see Section 5.12) and ButtonsText(han) contain the actual 
  1656. text in the button (see Section 5.11). 
  1657.  
  1658. If WinEvent returns a value of 2 (scrollable text line selected), then 
  1659. SaveText(i,j) contains the line of text that was selected (i.e., has focus); 
  1660. where: i=WinParms(CurWinPtr,18) and j=WinParms(CurWinPtr,15) 
  1661.  
  1662. Note that if the unmovable flag is set, then the window also cannot be resized 
  1663. (regardless of the state of the sizable flag).
  1664.  
  1665.  
  1666. 5.10 button handles
  1667. -------------------
  1668. When a push button, check box, input field or static text is created with 
  1669. LangWin's corresponding "make" or "show" routine, its data is stored in a 
  1670. "slot" of the ButtonsText and ButtonsData structures (described below). This 
  1671. "slot" is the index of the object's entry in these structures and is referred 
  1672. to as its "handle". The "make" routines return a handle value which should be 
  1673. saved in a unique variable name for later reference. 
  1674.  
  1675.  
  1676. 5.11 ButtonsText
  1677. ----------------
  1678. This structure is DIMed as follows: ButtonsText(1 to MaxButtons) AS STRING
  1679.  
  1680. If Han is the handle returned by the corresponding "make" or "show" routines,
  1681. then for each of the following objects, ButtonsText(Han) contains 
  1682. (see ButtonsData(i,8) in next section for button type):
  1683.  
  1684. BUTTON TYPE           CONTENTS OF ButtonsText(Han)
  1685. -----------           ----------------------------
  1686.  
  1687. Push Button: The push button's text (created with MakePushButton).
  1688.  
  1689. Check Box:   The symbol currently displayed in the check box (created with
  1690.              MakeCheckBox). By checking the state of the check box symbol's 
  1691.              shadow (see Section 5.12), you can determine if the box was 
  1692.              selected or not. 
  1693.  
  1694. Input Field: The current contents of the input field (created with 
  1695.              MakeInputField). Input fields can either be created with initial 
  1696.              text or a null string and can be modified by the user. By checking
  1697.              the contents of ButtonsText(handle) you can determine if the user
  1698.              made any changes (your code will have to "remember" the previous
  1699.              contents to determine if a change was made). If the input field is
  1700.              created (MakeInputField) with a negative value for length, then
  1701.              it can be used for password entry. All text entered will be 
  1702.              displayed with the * character, but the actual password will be
  1703.              saved in ButtonsText(handle).
  1704.  
  1705. Static Text: A line of static text placed into the window with the
  1706.              ShowWinText routine or a window title created with the
  1707.              ShowTitle routine. Each line of static text and each title 
  1708.              occupies a separate entry in ButtonsText (new with V2.1).
  1709.  
  1710.  
  1711. 5.12 ButtonsData
  1712. ----------------
  1713. This structure is DIMed as follows: ButtonsData(1 to MaxButtons, 1 to 10)
  1714. All values are initialized to -1.
  1715.  
  1716. Each push button, check box, input field, or static text has the following 8 
  1717. entries defined: 
  1718.  
  1719.      1 --- index to WinParms entry (i.e., the handle) of the window containing 
  1720.            this button.
  1721.            (0 if this entry is unused).
  1722.            (<0 if this object is not visible,
  1723.            i.e., window was resized smaller and object no longer fits). 
  1724.      2 --- button's current absolute row (relative to entire screen).
  1725.      3 --- button's current absolute column (relative to entire screen).
  1726.      4 --- length of button (in characters).
  1727.            (<0 if button is visible but inactive; see DeactivateButton in 6.1)
  1728.      5 --- foreground color attribute.
  1729.      6 --- background color attribute.
  1730.      7 --- current shadow state (0 = no shadow; 1 = shadow).
  1731.            [can be used to determine if check box is up (1) or down (0)]
  1732.      8 --- button type: 1 = push button, 2 = input field, 3 = check box
  1733.                         4 = static text.
  1734.      9 --- # rows in original window (used for resizing).
  1735.     10 --- # cols in original window (used for resizing).
  1736.  
  1737. For window titles, entry 8 will be a 4, and entries 2, 3, 4, 9, and 10 will be
  1738. a -1. 
  1739.  
  1740. Entries 2, 3, and 7 are dynamic and can change as button is moved or
  1741. (in the case of a check box) selected.
  1742.  
  1743. Examples: If you defined a check box in the current window, and saved its 
  1744. handle value (returned by MakeCheckBox) in C1, then you can test the value of 
  1745. ButtonsData(C1,7) after WinEvent returns control (regardless of the event) to 
  1746. determine the state of the check box. If ButtonsData(C1,7)=0, then the check 
  1747. box has no shadow and it is down. If ButtonsData(C1,7)=1, then the check box 
  1748. has a shadow, and it is up. 
  1749.  
  1750.  
  1751. 5.13 UserHotKeys
  1752. ----------------
  1753. WinEvent sets 3 standard action codes: 1 = close; 2 = text line selected; 3 = 
  1754. button selected. The UserHotKeys data structure is used to define additional 
  1755. GLOBAL hot keys (i.e., available from ALL open windows) and corresponding 
  1756. action codes. Under most circumstances, UserHotKeys should be defined once 
  1757. BEFORE the main WinEvent loop. 
  1758.  
  1759. Each user defined hot key has the following 2 entries in UserHotKeys:
  1760.            
  1761.      1 --- ASCII code (decimal) corresponding to the hot key. This is the code 
  1762.            that is returned by INKEY$ when the key is pressed. For 2-byte key 
  1763.            codes (for example Alt-z returns two bytes: 0 and 44), use the 
  1764.            negative value of the second byte (which would be -44 in the above 
  1765.            example). For 1-byte codes (i.e., Ctrl-z returns a 26, Shift-z 
  1766.            returns a 90, and z returns a 122), use the positive value of the 
  1767.            ASCII code. 
  1768.  
  1769.      2 --- WinEvent action code corresponding to the above key. WARNING: 
  1770.            action code must NOT be 1, 2, or 3. These are reserved for WinEvent 
  1771.            (if you choose action codes 1, 2, or 3, your hot key will not be 
  1772.            recognized). 
  1773.  
  1774.  
  1775. LangWin initializes UserHotKeys with 0 entries as follows:
  1776.     REDIM UserHotKeys(0,1 to 2)
  1777.  
  1778. If you want to define N specific GLOBAL hot keys,  then you must first REDIM 
  1779. the UserHotKeys array for N entries (i.e., REDIM UserHotKeys(0 to N, 1 to 2), 
  1780. and then define each hot key and its corresponding WinEvent action code in the 
  1781. UserHotKeys array (the 0th entry is required, but MUST be left empty). 
  1782.  
  1783. For example, to define 3 hot keys (q, Ctrl-v, and Alt-m) with corresponding 
  1784. WinEvent action codes (4, 5, 6), the following code would be needed: 
  1785.  
  1786.       REDIM UserHotKeys(0 TO 3, 1 TO 2)
  1787.       ' first hot key's definition
  1788.       UserHotKeys(1, 1) = 113   ' letter "q"
  1789.       UserHotKeys(1, 2) = 4     '   WinEvent action=4
  1790.       ' second hot key's definition
  1791.       UserHotKeys(2, 1) = 22    ' ctrl-v
  1792.       UserHotKeys(2, 2) = 5     '   WinEvent action=5
  1793.       ' third hot key's definition
  1794.       UserHotKeys(3, 1) = -50   ' alt-m
  1795.       UserHotKeys(3, 2) = 6     '   WinEvent action=6
  1796.  
  1797. ____________________________________
  1798. Notes: When REDIMing the UserHotKeys array, the lower bound of the first index 
  1799. MUST be 0. The 0th entry never contains hot key data, but it is required by 
  1800. LangWin. The upper bound of the first index must be the number of user defined 
  1801. hot keys required. 
  1802.  
  1803. User defined hot keys are active for ALL windows until the contents of 
  1804. UserHotKeys are changed or UserHotKeys is REDIMed to have 0 entries [i.e., 
  1805. REDIM UserHotKeys(0, 1 to 2) ]. By changing the contents of UserHotKeys "on the 
  1806. fly" you can dynamically change the GLOBAL hot keys and/or their action codes, 
  1807. but this is NOT recommended (at best, it would produce an inconsistent 
  1808. interface to your users since hitting a given hot key would produce different 
  1809. results at different times). 
  1810.  
  1811. You should not choose return codes 1, 2, or 3 for any user hot keys.
  1812.  
  1813. You cannot define any hot keys that are already used by WinEvent.
  1814. The keys used by WinEvent are:
  1815.  
  1816.     Ctrl-M  ---  generates code 13 which is ENTER (selects button with focus)
  1817.     Ctrl-I  ---  generates code  9 which is TAB (gives focus to next object)
  1818.     Ctrl-[  ---  generates code 27 which is ESC (close window event)
  1819.     Ctrl-a  ---  causes an "about" window to be displayed
  1820.     Ctrl-PgUp -  generates a code -132 (gives focus to next window)
  1821.  
  1822.  
  1823. 5.14 WinNum
  1824. -----------
  1825. This structure is DIMed as follows: WinNum(1 to MaxWindows). It is used as a 
  1826. cross reference between window handle and window number (see Section 5.7 for a 
  1827. discussion on the difference between these two values). WinNum(i) contains the 
  1828. window number for window handle i. WinNum is new with V2.0.
  1829.  
  1830.  
  1831.  
  1832. --------------------
  1833. 6.0 ADVANCED WINDOWS
  1834. --------------------
  1835. Well, if you made it this far in LangWin's user's guide, you are a true hacker
  1836. (I use that term, as it was originally defined when computers had vacuum tubes,
  1837. as a compliment for someone who truly wants to understand and use all of the 
  1838. intricacies of a system). I'll share a few hints, tips, and secrets for getting
  1839. more miles/gallon from LangWin. Most of this section was re-written for 
  1840. LangWin 2.0; I encourage users of LangWin 1.x to read this section is detail.
  1841. In addition, you should read the description of every routine in WINHELP.BAS
  1842. (not every LangWIn routine is described in this user's guide).
  1843.  
  1844.  
  1845. 6.1 Adding Frills to Your Windows
  1846. ---------------------------------
  1847. LangWin has a number of routines for adding frills to your windows. I'll cover 
  1848. some them briefly here. Load WINHELP.BAS into QB and hit F2 to see a detailed 
  1849. description of ALL routines (i.e., all of LangWin's routines are not described
  1850. in the user's guide; WINHELP.BAS is the real reference guide for LangWin). 
  1851.  
  1852. In general, you can specify the position, color, and contents of various 
  1853. objects to be placed in the window . These routines should be called just after 
  1854. you create a given window and before you create another window or wait for 
  1855. events. 
  1856.  
  1857.  ChangeButtonFocus - reverse video a button's text to show it has focus
  1858.  MakeBox           - place a single/double line box in the window
  1859.  MakeHorizLine     - draw a horizontal line across the window
  1860.  MakeVertLine      - draw a vertical line across the window
  1861.  ShowTitle         - place a title, centered, at top of the window
  1862.  ShowWinText       - place some text in the window
  1863.  
  1864.  
  1865. See SAMPLE0x.BAS,  included on your LangWin distribution disk, for sample code 
  1866. that uses the above routines. 
  1867.  
  1868.  
  1869.  
  1870. 6.2 Window Modes, Shadows, and Movement
  1871. ---------------------------------------
  1872. With LangWin 2.0, there are four modes that can be assigned to a window
  1873. when it is opened (see descriptions of BlankWin and OpenScrollWindow
  1874. for calling parameters and values):
  1875.  
  1876. Modeless:       This is a "normal" window. When it has focus, you can click on
  1877.                 any other visible window, and the new window will be given 
  1878.                 focus.
  1879.  
  1880. Modal:          When a modal window has focus (just after it is opened), 
  1881.                 clicking on any other visible window will NOT produce an event.
  1882.                 This type of window can be used to display an error or warning
  1883.                 message that you want the user to read and acknowledge (by 
  1884.                 either clicking on an "OK" button in the window, or by double
  1885.                 clicking the close icon). Your code should then close the 
  1886.                 window. In most cases, the modal window ALWAYS retains focus 
  1887.                 until it has been closed. Clicking other windows will NOT give
  1888.                 them focus. (An exception would occur if you placed a button in
  1889.                 a modal window that caused another window to be opened. This new
  1890.                 window could any mode - which might result in some interesting
  1891.                 bugs, so I don't recommend opening any new windows while a 
  1892.                 modal window has focus. After any event occurs in a modal 
  1893.                 window, just close the window. The point is that while a modal
  1894.                 window has focus, NO OTHER window can be given focus or
  1895.                 generate an event.
  1896.  
  1897. Immediate Close: When this window has focus, clicking on any other visible
  1898.                 window will automatically generate a close action code (just
  1899.                 as if the close icon was double clicked). The immediate close
  1900.                 type window can be used to display pull down menus. If a pull
  1901.                 down menu is visible, and the user clicks elsewhere, a close
  1902.                 action code is returned and the pull down menu is closed
  1903.                 (by your program's responding to the close action code). If you
  1904.                 want your pull down menu to remain on the screen when the user
  1905.                 clicks elsewhere, make it a modeless type.
  1906.                 
  1907. Wallpaper:      This is a static or background only window. It can NEVER get
  1908.                 focus, NEVER have any actions, and NEVER be moved. WinEvent
  1909.                 recognizes when a wallpaper window is clicked and ignores the 
  1910.                 action. Wallpaper windows can be used to display static
  1911.                 information or as background for other windows (see 
  1912.                 Section 6.3). You do not need to test for any events in a 
  1913.                 wallpaper window. If you need to reuse the screen space 
  1914.                 occupied by a wallpaper window, you will have to manually make
  1915.                 it current and close it (since the user cannot directly cause a 
  1916.                 close event for that window). 
  1917.  
  1918.                 Wallpaper window mode can only be selected from the BlankWin
  1919.                 routine (OpenScrollWindow cannot create a wallpaper window).
  1920.                 It goes without saying that you should not create any objects
  1921.                 (buttons, etc) in a wallpaper window (you can place static
  1922.                 text in a wallpaper window). Since wallpaper windows cannot 
  1923.                 have any actions, you cannot create a wallpaper window with a
  1924.                 close icon.
  1925.  
  1926. In addition to the window's mode, the window can have three other attributes: 
  1927. shadow/shadowless, movable/unmovable, and sizable/not-sizable. These are self 
  1928. explanatory. The shadow feature is controlled by the sign of the mode parameter 
  1929. in BlankWin and OpenScrollWindow. If the mode parameter is negative, the window 
  1930. is shadowless. The movable feature is controlled by the sign of the window 
  1931. color parameter in BlankWin and OpenScrollWindow. If the window color is 
  1932. negative, then the window will be unmovable. The sizable feature is controlled
  1933. by the sign of the border color parameter in BlankWin and OpenScrollWindow.  
  1934. A negative value will prevent the window from being resized (in addition, if 
  1935. the window is unmovable, it cannot be resized - regardless of the state of the 
  1936. sizable flag).
  1937.  
  1938.  
  1939. 6.3 Using Wallpaper Windows
  1940. ---------------------------
  1941. Wallpaper windows can NEVER get focus and NEVER generate any actions. Two 
  1942. possible uses are: Information Only windows and background windows (to give 
  1943. the "illusion" of multiple scrollable lists in one window). The following 
  1944. sections describe these two techniques. 
  1945.  
  1946.  
  1947. 6.3.1 Information Only Windows
  1948. ------------------------------
  1949. You should use WinEvent to wait for an event from any open window. WinEvent 
  1950. will return the window's number and an action code. These will define where the 
  1951. event occurred (window number) and what object caused the event (action code). 
  1952. In general, after control returns from WinEvent, you must test for every 
  1953. possible window number that could be open by comparing the window number 
  1954. returned from WinEvent (which defines the window that had focus when the event 
  1955. occurred) to the set of unique window numbers that were returned by all of the 
  1956. BlankWIn or OpenScrollWindow routines used to create windows. 
  1957.  
  1958. If, however, you wish to create an "information only" window that can NEVER 
  1959. have any user actions (including closing it!), then you need not test for the 
  1960. information window's number in your WinEvent loop. In the simplest case, where 
  1961. you only want to place an info window on the screen and no other windows, then 
  1962. you don't even need a WinEvent loop. Making the Info Window's mode 4 will 
  1963. insure that no events can occur from the information window. 
  1964.  
  1965. Remember, the info window cannot be selected or closed by the user (you can 
  1966. close it with the CloseWindow routine as long as you manually make it current 
  1967. before calling CloseWindow - see CloseWindow in WINHELP.BAS for an example
  1968. of how to do this). Also, remember that if you have info windows open, the 
  1969. AnyWinOpen global variable will remain TRUE. Thus, using "DO WHILE AnyWinOpen" 
  1970. to control your WinEvent loop will never exit because the info window will 
  1971. remain open (and AnyWinOpen will be TRUE) even after all other windows are 
  1972. closed. In this case, you'll have to explicitly break out of the loop (i.e., 
  1973. EXIT DO) when you detect a close event (action=1) in your main window. 
  1974.  
  1975. One example would be to display instructions that need to remain on the 
  1976. screen for subsequent windows. Open a window and display the instructions (see 
  1977. ShowWinText). Then open another window (which becomes the active window) and 
  1978. loop through WinEvent waiting for events. If the instruction window is Mode 4, 
  1979. it cannot be moved by the user. It should be positioned so that subsequent 
  1980. windows do not overlay it (thus obscuring the information you wanted to 
  1981. display). Remember that after you close all subsequent windows, the instruction 
  1982. window again becomes the active window and should be closed. 
  1983.  
  1984.  
  1985. 6.3.2 Multiple Scrollable Lists In One Window
  1986. ---------------------------------------------
  1987. LangWin only supports one scrollable list per window. There are times when 
  1988. you'll want to provide the "illusion" of several scrollable lists in one 
  1989. window. Open a shadowed wallpaper window, then open several scrollable lists 
  1990. "on top" of the wallpaper window, using the same color as the wallpaper. Make 
  1991. these windows shadowless and unmovable. The user will "see" one window with 
  1992. multiple scrollable lists. Your program will be responding to several windows, 
  1993. all of which happen to be of the same color as the wallpaper window. Since the 
  1994. wallpaper window can NEVER be given focus (WinEvent makes sure of this), you 
  1995. don't have to worry that user will click the wallpaper, make it current, and 
  1996. cause it to "overlay" (i.e., hide) all other windows that were placed "over" 
  1997. it. SAMPLE04.BAS contains code that implements this technique. 
  1998.  
  1999. When you use the above technique to open several windows, giving the illusion 
  2000. that they all are really one window, you will want that window to appear to be 
  2001. modal. That is, all mouse clicks on windows other than the "multiple window" 
  2002. should be ignored until the multiple window is closed (otherwise portions of 
  2003. the multiple window would get overlaid, impacting the illusion that the 
  2004. multiple window is one entity). The "multiple window" is just that: several 
  2005. windows. How does one prevent mouse clicks from being accepted on windows 
  2006. other than the "multiple window", while allowing mouse clicks on any of the 
  2007. component windows that make up the multiple window? Good question! I'm glad 
  2008. you asked. First, you can't just make all component windows of the multiple 
  2009. window modal. This would result in only the last component of the multiple 
  2010. window accepting mouse clicks (if the last component window is modal, WinEvent 
  2011. will restrict mouse clicks that window).
  2012.  
  2013. If there are no other windows open when the multiple window is created, 
  2014. there's no problem (because there's no other windows where the mouse could be 
  2015. clicked). However, if other windows exist when the multiple window is created, 
  2016. these existing windows must not be able to accept mouse clicks while the 
  2017. multiple window is open. In order to accomplish this, temporarily set all 
  2018. windows that exist prior to creating the multiple window to wallpaper mode. As 
  2019. wallpaper, WinEvent will ignore any events in these windows. The components of 
  2020. the multiple window can then be opened as modeless (allowing actions in any of 
  2021. the components). 
  2022.  
  2023. The following code shows this technique for one existing window whose number 
  2024. is saved in Main1: 
  2025.  
  2026.         x=IsWinOpen(Main1,han)   ' get Main1's handle
  2027.                                  ' assume you KNOW it's open, and no need to
  2028.                                  ' test return from IsWinOpen for TRUE.
  2029.         omode=WinParms(han,19)   ' save main window's current mode
  2030.         WinParms(han,19)=4       ' set mode to wallpaper
  2031.  
  2032.         ' now open multiple windows and process events
  2033.            .
  2034.            .
  2035.            .
  2036.         ' done with multiple windows, close them all
  2037.  
  2038.         WinParms(han,19)=omode   ' restore original mode
  2039.  
  2040.  
  2041.  
  2042. 6.4 Modifying Scrollable Text While Its Window Is Open
  2043. ------------------------------------------------------
  2044. All scrollable text is saved in the SaveText array (see Section 5.8). One use 
  2045. for scrollable text is to present a list of items that can be selected for 
  2046. later action (e.g., a list of files to be printed, deleted, etc). The user 
  2047. would scroll through the list and select desired items by double clicking each 
  2048. one. After all items have been selected, an "action" button would be clicked to 
  2049. process all previously selected items. 
  2050.  
  2051. In order to implement this function, you must first give the user feedback that 
  2052. the text line clicked has actually been selected. One possible way to do this 
  2053. is to include specific characters in the scrollable text that can be used to 
  2054. denote selection or un-selection. For example, every line of scrollable text 
  2055. could begin with [ ] (that is, left bracket, space, right bracket) if it is not 
  2056. selected, and [X] if it is selected. 
  2057.  
  2058. When a line of text is double clicked, it is given focus and control is 
  2059. returned from WinEvent. The value returned from WinEvent is the window's 
  2060. number. The value returned in the action code will be a 2. Your code would 
  2061. examine the window's number and action code, and give control to the proper 
  2062. code segment (see Section 3.2). At that point, CurWinPtr (a global variable, 
  2063. see Section 5.6) will contain the current window's handle. SaveText(i,j) will 
  2064. contain the scrollable text with focus [where: i=WinParms(CurWinPtr,18) and 
  2065. j=WinParms(CurWinPtr,15)]. 
  2066.  
  2067. To denote selection of the text line in focus, your program would first have to 
  2068. change the second character in SaveText(i,j) to an "X". The text line would 
  2069. then begin with [X] to indicate selection. Actually, you would first want to 
  2070. test the contents of the selected text line's second character, so you could 
  2071. toggle a space to an X, and an X to a space (thus, the user could click on the 
  2072. text and toggle the selection on/off). 
  2073.  
  2074. Once you've changed the scrollable text's selection character (on  or off), 
  2075. you'll need to actually update the contents of the visible window. To do this, 
  2076. you must re-write that line of text into the proper position of the window. The 
  2077. ReShowText routine will accomplish the necessary refresh into the current 
  2078. window. After you refresh the window, continue looping through WinEvent. 
  2079.  
  2080. When the user finally selects the "action" button, WinEvent will return an 
  2081. action code of 3. After determining which window and which button was selected, 
  2082. you can take appropriate action on all text lines selected. Merely step through 
  2083. every entry in the current window's scrollable text, examine the second 
  2084. character, and if it's an X, take action. The current window's scrollable text 
  2085. can be found in SaveText(i,x) where: i=WinParms(CurWinPtr,18) and x = 1 to 
  2086. WinParms(CurWinPtr,17). 
  2087.  
  2088. In addition, you should re-set the selection, by changing the X back to a blank 
  2089. in the text array. Again, you must update the contents of the window to show 
  2090. that all previously selected items have now been un-selected. The ReShowPage 
  2091. routine will accomplish this task (ReShowText CANNOT be used since it ONLY 
  2092. refreshes the current line of text that has focus, and you may need to refresh 
  2093. many text lines). After you refresh the window, continue looping through 
  2094. WinEvent. 
  2095.  
  2096. SAMPLE02.BAS has sample code that implements the above technique.
  2097.  
  2098.  
  2099. 6.5 Changing the Entire Scrollable Text Array While its Window is Open
  2100. ----------------------------------------------------------------------
  2101. The previous section described how you can change individual lines of 
  2102. scrollable text in an open window. It is also possible to replace an open 
  2103. window's scrollable text with an entirely new set. The new set can either have 
  2104. more, less, or the same number of lines. For example, if your window displays a 
  2105. directory structure and contents, and the user changes directories, you may 
  2106. want to show a completely different list of file names in the window. 
  2107.  
  2108. The RefreshScrollText routine (new with V2.0) can be used to replace the 
  2109. scrollable text in the current window with focus. If the window to be updated 
  2110. is not current, you must manually make it current (see RefreshScrollText in 
  2111. WINHELP.BAS for an example of how to do this). You must place the new 
  2112. scrollable text into a string array whose LBOUND is 1. This string array is 
  2113. used as a parameter to the RefreshScrollText routine (see WINHELP.BAS for 
  2114. additional details). Run time errors will occur if the current window with 
  2115. focus has no scrollable text or LBOUND of the string array is not 1. After 
  2116. control is returned from RefreshScrollText, I recommend that you ERASE the 
  2117. string array (passed as a parameter to RefreshScrollText) in order to save 
  2118. memory. If the UBOUND of your string array is greater than MaxTextLines, then 
  2119. only the first MaxTextLines of the array will be displayed, and the 
  2120. MaxTextLines entry will appear as:   (Incomplete List)   to let your user know 
  2121. that all data is not visible. See Section 5.3 for additional details on 
  2122. programming to handle this case. 
  2123.  
  2124.  
  2125.  
  2126. SAMPLE04.BAS contains examples of techniques to modify the contents of
  2127. scrollable arrays while a window is open.
  2128.  
  2129.  
  2130. 6.6 Modifying the Contents of an Input Field While Its Window Is Open
  2131. ---------------------------------------------------------------------
  2132. Similar to the technique for modifying scrollable text (see Section 6.4), you 
  2133. might need to modify the contents of an input field based upon other events in 
  2134. the window (for example, the WINCOLOR routine, included on the LangWin 
  2135. distribution disk, has input fields that can be updated directly or 
  2136. incremented/decremented by selecting a push button). When a push button is 
  2137. selected, WINCOLOR updates the corresponding input field (i.e., increments or 
  2138. decrements the current value and redisplays the updated value). 
  2139.  
  2140. Your program's logic will have to determine the handle of the input field that 
  2141. should be updated. This can be done in response to a specific event in the 
  2142. window (i.e., when a specific button is clicked, you may need to update a 
  2143. specific input field). Let's call that handle: Han. To modify the corresponding 
  2144. input field's contents, just change the appropriate characters in 
  2145. ButtonsText(Han). Remember that ButtonsText is a STRING array. If the contents 
  2146. represent numeric data, use the VAR command to convert to numeric, modify, and 
  2147. use STR$ to place the equivalent string values back into ButtonsText(Han). 
  2148.  
  2149. After the ButtonsText array has been updated, the window must be refreshed. Use 
  2150. ReShowInputField to accomplish this task (similar to ReShowText in Section 
  2151. 6.4). After the input field has been updated and redisplayed, continue with the 
  2152. WinEvent loop. 
  2153.  
  2154.  
  2155. 6.7 Determining What Had Focus When WinEvent Returns Control
  2156. ------------------------------------------------------------
  2157. When control is returned from WinEvent, you will need to determine two things: 
  2158. which window had focus and what action occurred in that window. The following 
  2159. sub-sections address these two event-driven programming tasks. 
  2160.  
  2161. 6.7.1 Determining Which Window Had Focus
  2162. ----------------------------------------
  2163. As described in Section 5.7, the WinEvent function returns a value that 
  2164. corresponds to the number of the window that had focus when an action occurred. 
  2165. When every window is created (by either BlankWin or OpenScrollWindow), it is 
  2166. assigned a unique window number (value returned by the function). You should 
  2167. save these window numbers in unique variables (if the value returned is < 0, 
  2168. then an error has occurred when creating the window, see Section 6.14 for more 
  2169. details on handling errors). When control is returned from WinEvent, you need 
  2170. to compare the window number returned (by WinEvent) to the set of all window 
  2171. numbers saved when your windows were created. When you find a match, you know 
  2172. what window had focus (and you can then determine which action occurred in that 
  2173. window - see Section 6.7.2). 
  2174.  
  2175. The easiest way to implement the above technique is with a SELECT CASE 
  2176. structure. Assume that three windows have been created, and their numbers are 
  2177. saved in variables: w1, w2, and w3. The following pseudo code will determine 
  2178. which window had focus when an event occurs: 
  2179.  
  2180.         ' open some windows
  2181.         w1=BlankWin(parms)
  2182.         w2=OpenScrollWindow(parms)
  2183.         w3=BlankWin(parms)
  2184.  
  2185.         do while AnyWinOpen  ' loop as long as windows are open
  2186.             ' wait for an event, window number returned in variable: wnum    
  2187.             wnum=WinEvent(action)   
  2188.             select case wnum   ' determine which window had focus
  2189.             case w1
  2190.                 ' process actions for window: w1
  2191.             case w2
  2192.                 ' process actions for window: w2
  2193.             case w3
  2194.                 ' process actions for window: w3
  2195.             end select
  2196.         loop
  2197.  
  2198.  
  2199. The above code handles static windows: w1, w2, and w3, that is windows 
  2200. specifically opened in your code before waiting for events. Your WinEvent loop 
  2201. must test for every static window that was opened. However, the code that 
  2202. processes events for a specific window might also open windows dynamically, 
  2203. that is under control of your end user and the events that are selected at run 
  2204. time. Thus, your WinEvent loop must not only test for all possible static 
  2205. windows, but also all possible dynamic windows. 
  2206.  
  2207. For example, in the above code, assume that in window w2, a new window should 
  2208. be opened (number saved in w2a) when a specific event occurs (a button click). 
  2209. Then, your loop must also include a CASE statement for w2a (to handle any 
  2210. events that could occur if/when window w2a is open and current). The code new 
  2211. might look like: 
  2212.  
  2213.         ' open some windows
  2214.         w1=BlankWin(parms)
  2215.         w2=OpenScrollWindow(parms)
  2216.         w3=BlankWin(parms)
  2217.  
  2218.         do while AnyWinOpen     ' loop as long as windows are open
  2219.             wnum=WinEvent(action)   ' wait for an event
  2220.             select case wnum     ' determine which window had focus
  2221.             case w1
  2222.                 ' process actions for window: w1
  2223.             case w2
  2224.                 ' process actions for window: w2
  2225.                         .
  2226.                         .
  2227.                         .
  2228.                  if specific button pressed then
  2229.                    w2a=BlankWin(parms)'open a dynamic window under user control
  2230.                  end if
  2231.                         .
  2232.                         .
  2233.                         .
  2234.             case w3
  2235.                 ' process actions for window: w3
  2236.             case w2a
  2237.                 ' process actions for window :w2a
  2238.             end select
  2239.         loop
  2240.  
  2241. Thus, as you begin developing code segments to handle every possible event, you 
  2242. will find yourself adding additional segments to handle dynamic windows that 
  2243. can be open due to actions or errors. 
  2244.  
  2245. 6.7.2 Determining What Action Occurred In The Window
  2246. ---------------------------------------------------
  2247. WinEvent takes one parameter. Upon return, this parameter is set to an action 
  2248. code: 1=close; 2=scrollable text; 3=button.
  2249.  
  2250. Typically, the code segment for each window will have to test the action code 
  2251. (returned by WinEvent) and take appropriate action. Again, the SELECT CASE 
  2252. structure can be used. The following pseudo code would reside within the 
  2253. segment for a given window (window w2 is used in the example): 
  2254.  
  2255.                 .
  2256.                 .
  2257.        do while AnyWinOpen   ' loop as long as long as windows are open
  2258.          wnum=WinEvent(action)   ' wait for an event
  2259.          select case wnum     ' determine which window had focus
  2260.  
  2261.                 .
  2262.                 .
  2263.          case w2
  2264.              ' process actions for window w2
  2265.              select case action
  2266.              case 1
  2267.                 ' process the close action in window w2
  2268.              case 2 
  2269.                 ' process the selected scrollable text in window w2
  2270.              case 3
  2271.                 ' process the button clicked in window w2
  2272.              end select
  2273.                 .
  2274.                 .
  2275.          end select
  2276.        loop
  2277.  
  2278.  
  2279.  
  2280. If the action code was 2, then a line of scrollable text was selected (i.e., it 
  2281. has focus). The selected line of text can be found in SaveText(i,j); where: 
  2282. i=WinParms(CurWinPtr,18) and j=WinParms(CurWinPtr,15). In this case, no button 
  2283. could have had focus (i.e., when a line of text is clicked, focus is removed 
  2284. from any button). Process SaveText(i,j) as necessary (see Section 6.4 for an 
  2285. example). 
  2286.  
  2287. If the action code was 3, then a button was clicked. Your code segment must 
  2288. determine which button has focus (if there were more than one buttons in the 
  2289. window). WinParms(CurWinPtr,16) contains the handle of the button with focus. 
  2290. Use this value in a SELECT CASE to process every possible button created in the 
  2291. given window. Button handle values are returned by the MakePushButton routine 
  2292. and should be saved in unique variable names. These variables will then be used 
  2293. in your CASE statements. If a button was clicked, it is given focus and control 
  2294. returned from WinEvent. In this case, scrollable text could also have focus (if 
  2295. scrollable text exists). Your code segment will have to determine if any 
  2296. actions should be taken with any scrollable text that also has focus. 
  2297.  
  2298. The following code segment shows how you might process a close action, clicking 
  2299. on scrollable text, or clicking on a button in a given window (w2). If button 
  2300. w2b2 is clicked, a dynamic window is opened. 
  2301.  
  2302.                 .
  2303.                 .
  2304.         w2=OpenScrollWindow(parms)  ' open a window
  2305.         w2b1=MakePushButton(parms)  ' create buttons in
  2306.         w2b2=MakePushButton(parms)  '    the window
  2307.                 .
  2308.                 .
  2309.      do while AnyWinOpen   ' loop as long as windows are open
  2310.         wnum=WinEvent(action)  ' wait for an event
  2311.         select case wnum    ' determine which window has focus
  2312.                 .
  2313.                 .
  2314.                 .
  2315.         case w2       ' process events in window: w2
  2316.                  select case action    ' determine which action occurred
  2317.                  case 1
  2318.                     ' process the close action in window w2
  2319.                     xx=CloseWindow      ' close the window 
  2320.                  case 2 
  2321.                     ' process the selected scrollable text in window w2
  2322.                     slot=WinParms(CurWinPtr,18) ' slot with window's text set
  2323.                     row=WinParms(CurWinPtr,15)  ' row of text with focus
  2324.                     process SaveText(slot,row)
  2325.                  case 3
  2326.                     ' process the button clicked in window w2
  2327.                     select case WinParms(CurWinPtr,16) 'determine which button  
  2328.                     case w2b1
  2329.                         ' process a click on button: w2b1
  2330.                     case w2b2
  2331.                         ' process a click on button: w2b2
  2332.                         ' open a new window if button w2b2 is clicked
  2333.                         w5=OpenScrollWindow(parms)
  2334.                     end select
  2335.                  end select
  2336.                 .
  2337.                 .
  2338.         end select
  2339.      loop
  2340.  
  2341.  
  2342. Once you understand the above technique, refer to SAMPLE0x.BAS, included on the 
  2343. LangWin distribution disk, for complete code that implements windows. If you 
  2344. need to reference LangWin's routines and their actual parameters, load 
  2345. WINHELP.BAS (which was included on LangWin's distribution disk) into QB and hit 
  2346. F2. 
  2347.  
  2348.  
  2349. 6.8 Nesting Calls to WinEvent
  2350. -----------------------------
  2351. As you can see from the previous code examples, things can get complex very 
  2352. quickly. Your WinEvent loop must have a CASE for every possible window (both 
  2353. static and dynamic). Within each code segment that processes a window, you need 
  2354. CASE statements for every possible action code (at least codes 1-3 plus any 
  2355. codes for user defined hot keys). Then, within the code segment to handle 
  2356. action 3 (button click), you need a CASE statement for every button created in 
  2357. that window. For a complex set of windows, with several menus, sub-menus, 
  2358. buttons, user hot keys, and dynamic error windows, your code will be long. 
  2359.  
  2360. One way to make your code more readable is to perhaps limit the main module to 
  2361. just the CASE statements for all windows. Once you determine which window had 
  2362. focus, you could call a separate subroutine to process each window. The 
  2363. subroutine would have to be aware of the button handles created for its window 
  2364. in the main program, and if the subroutine opens any windows and saves their 
  2365. handles in variables, the main routine must have access to these variables 
  2366. (because the main module needs a CASE statement for every possible window). A 
  2367. good exercise in sharing variables. 
  2368.  
  2369. The subroutine that processes events for a given window could create child 
  2370. windows and have its own WinEvent loop. In this case, that WinEvent loop would 
  2371. only be "aware" of events in windows it was programmed to respond to (i.e., 
  2372. child windows opened while control was in the subroutine). Clicking other 
  2373. windows and objects would have no effect until the subroutine returned control 
  2374. back to the main module. In some circumstances, this technique might not only 
  2375. make your code simpler to understand/debug, but may be exactly the method you 
  2376. need to process child windows. Care should be taken in nesting calls to 
  2377. WinEvent (from within a WinEvent loop, calling a subroutine that has its own 
  2378. call to WinEvent and loop, which in-turn calls a subroutine with a WinEvent 
  2379. loop, etc.). I've had stack overflows when trying to nest too many calls to 
  2380. WinEvent. (What "too many" is depends upon memory availability. I'd recommend 
  2381. that you don't nest more than 3 or 4, after that your code is probably far too 
  2382. complex to deal with anyway). 
  2383.  
  2384.  
  2385. 6.9 Deactivating and Activating Buttons
  2386. ---------------------------------------
  2387. The pseudo code in the previous sections demonstrated how you might open a 
  2388. dynamic window when a specific event occurred (i.e., a button click). 
  2389. Typically, when this new window has been opened, you may want to prevent the 
  2390. end user from continuing to click the same button and opening more windows of 
  2391. the same kind (this could quickly cause MaxWindows, maximum number of windows 
  2392. that can be open, to be exceeded and perhaps your program to fail). One way to 
  2393. prevent additional windows from being opened when the same button is clicked is 
  2394. to make the window's mode either Modal or Immediate Close (see Section 6.3 for 
  2395. details). In the case of a Modal window, the user MUST close the window before 
  2396. any other event can take place (thus clicking the same button again is not 
  2397. possible until the dynamic window is first closed). In the case of an Immediate 
  2398. Close window, clicking the same button will first result in a close action for 
  2399. the dynamic window (i.e., clicking anywhere off the Immediate Close window 
  2400. will cause it to be closed). 
  2401.  
  2402. Both of the above techniques (Modal and Immediate Close) have their 
  2403. disadvantages. In particular, you may want to allow the user to mouse elsewhere 
  2404. (while the new dynamic window is open) and select other objects (except the 
  2405. button that originally caused the dynamic window to be opened). You may also 
  2406. want the new dynamic window to remain open while the user mouses elsewhere. 
  2407.  
  2408. To get around these disadvantages, you can use the DeactivateButton routine. 
  2409. This will clear the button's text and make it inactive. While the button is 
  2410. inactive, no action on that button will be recognized by WinEvent (i.e., 
  2411. clicking the button will not cause a return from WinEvent). When you are ready 
  2412. to accept actions from the given button again (i.e., after the new dynamic 
  2413. window has been closed), then call the ActivateButton routine. See WINHELP.BAS 
  2414. for details on how to call these routines. 
  2415.  
  2416.  
  2417. 6.10 Giving a Specific Button Focus When It Is Created
  2418. ------------------------------------------------------
  2419. When buttons or check boxes are created (with the corresponding "make" 
  2420. routine), they are not given focus. Hitting TAB or an arrow key will cause the 
  2421. "next" object to get focus (and be displayed in reverse video). Hitting ENTER 
  2422. will then cause control to be returned from WinEvent with an action code of 3. 
  2423. WinParms(CurWinPtr,16) will contain the handle of the button in focus. Clicking 
  2424. on the button will also cause these events to occur.  
  2425.  
  2426. As you create buttons in a window, you might want to give one of them
  2427. focus (i.e., make it the default choice). Your user could then click this 
  2428. button to select it, or just hit ENTER (since it will already have focus).
  2429. The following code should be used to give a specific button focus (assume
  2430. that the button's handle, returned from the corresponding "make" routine,
  2431. is saved in Han):
  2432.  
  2433.              WinParms(CurWinPtr,16)=Han    ' place handle in data structure
  2434.              CALL ChangeButtonFocus(Han,0) ' give button visual focus 
  2435.  
  2436. The above code MUST be placed AFTER the corresponding window has been created
  2437. (with BlankWin or OpenScrollWindow), AFTER the button has been created (with
  2438. a "make" routine), and BEFORE the next window is created (i.e., CurWinPtr 
  2439. must point to the current window where the button will be given focus - see 
  2440. Section 5.6). 
  2441.  
  2442. Only ONE button (or check box) per window can be given focus. 
  2443. WinParms(CurWinPtr,16) contains its handle. You could call ChangeButtonFocus 
  2444. multiple times to reverse video many buttons, but only the button whose handle 
  2445. is found in WinParms(CurWinPtr,16) will be recognized by WinEvent when 
  2446. processing mouse or keyboard input. (Calling ChangeButtonFocus for more than 
  2447. one button will only confuse your user).
  2448.  
  2449.                                         
  2450. 6.11 Is A Given Window Open
  2451. ---------------------------
  2452. On occasion, you may need to determine if a specific window is open. For 
  2453. example, if you receive a click on an EXIT button, you may want to determine if 
  2454. any child windows have been opened dynamically (and close them first). Of 
  2455. course, you could have deactivated the EXIT button (see Section 6.8) when a 
  2456. child window is opened (which will prevent EXIT from being clicked until you 
  2457. activate the button when the child window is closed). However, let's assume 
  2458. that you will allow the user to click the EXIT button and automatically close 
  2459. any dynamically opened child windows along with the main window. 
  2460.  
  2461. The IsWinOpen function (new with 2.0) can be used for this purpose. Its input 
  2462. parameter is the window's number (NOT the window handle). It returns a TRUE 
  2463. value if the window is open; else it returns a FALSE value. IsWinOpen also 
  2464. takes a second (output) parameter. If the window number passed is open, the 
  2465. second parameter is set to the window's handle (thus IsWinOpen will also 
  2466. provide a window number to window handle cross reference function - also see 
  2467. Section 5.14). 
  2468.  
  2469. See WINHELP.BAS for additional details on IsWinOpen.
  2470.  
  2471. 6.12 Manually Giving a Window Focus (i.e., via program control)
  2472. ---------------------------------------------------------------
  2473. When WinEvent has control, it will detect when the mouse is clicked on a window 
  2474. and (if appropriate) give that window focus (so that any subsequent objects 
  2475. selected in that window will cause control to be returned). The global variable 
  2476. CurWinPtr contains the handle of the window with focus.
  2477.  
  2478. There may be occasions when your program will need to cause a specific window 
  2479. to obtain focus. The NewFocusWindow routine takes a window's handle as its 
  2480. parameter, and will cause that window to be given focus. 
  2481.  
  2482. For example, if a main window has an EXIT button, and the button is selected, 
  2483. then the main window should be closed. However, before the main window is 
  2484. closed, all open child windows should probably be closed (of course there are 
  2485. exceptions to this "rule"). The IsWinOpen (see previous section) can be used to 
  2486. determine if a specific child window is open (given the child window's number), 
  2487. and if so it's handle will be returned. Using that handle of each open child 
  2488. window, NewFocusWindow can be used to first give it focus, then close it (the 
  2489. CloseWindow routine closes the current window, so each child must first be made 
  2490. current before it can be closed). 
  2491.  
  2492. WARNING: NewFocusWindow will cause your program to terminate if an invalid 
  2493. handle is passed to it. The handle must correspond to an open window. One way 
  2494. to insure that you have a valid handle is to use the IsWinOpen routine which 
  2495. will return the handle of an open window (given that the window is open and you 
  2496. pass IsWinOpen it's window number).
  2497.  
  2498. 6.13 State of Check Boxes
  2499. -------------------------
  2500. Clicking on a check box will change its state, but will NOT return an event 
  2501. from WinEvent. However, when an event does occur and control is returned from 
  2502. WinEvent, you may want to check the state of any check boxes in the current 
  2503. window. If you defined a check box in the current window, and saved its handle 
  2504. value (returned by MakeCheckBox) in C1, then you can test the value of 
  2505. ButtonsData(C1,7) after WinEvent returns control (regardless of the event) to 
  2506. determine the state of the check box. If ButtonsData(C1,7)=0, then the check 
  2507. box has no shadow and it is down. If ButtonsData(C1,7)=1, then the check box 
  2508. has a shadow, and it is up. 
  2509.  
  2510.  
  2511.  
  2512. 6.14 Run Time Errors
  2513. -----------------------
  2514. Many of LangWin's functions return codes indicating success or failure. For 
  2515. those routines whose parameters are static (not changable based upon user input 
  2516. at run time, but constants hard-coded in the parameter lists), you'll find most 
  2517. errors during development. For example, if a window fails to open, you can 
  2518. insert a breakpoint, check the return code, and figure out the error (i.e., 
  2519. window won't fit on the screen, etc.). You could also place instructions after 
  2520. the CALL to these functions, test the return code, and print it if an error 
  2521. value is indicated (see WINHELP.BAS for a description of every routine and its 
  2522. return codes). I'd recommend this technique (i.e., testing return codes for 
  2523. error values) in all cases where the parameters to LangWin's functions are 
  2524. dynamic (i.e., based upon conditions that can be changed during run time). 
  2525.  
  2526. If a window fails to open (for example, because it will not fit on the screen), 
  2527. and you don't test for this error, then subsequent references to LangWin's data 
  2528. structures using CurWinPtr will reference the last window with focus. This will 
  2529. either result in a run time error (subscript out of range) or unpredictable 
  2530. results in your program. 
  2531.  
  2532. For example, with V2.1 resizing is supported. In addition to saving objects
  2533. (i.e., buttons, check boxes, input fields) in data structures, window titles
  2534. and static text must also be saved (new with V2.1). The global parameter 
  2535. MaxButtons determines the size of these data structures. If MaxButtons is too 
  2536. small, then the routines that create objects, titles, and static text will 
  2537. return an error code and the object will not be created. If you don't test for 
  2538. this error, you'll have windows that will be missing some/all expected objects
  2539. (i.e., you could end up with an empty window). While this won't cause a fatal 
  2540. error, your windows might not contain the information you expect or need. All 
  2541. of the windows/objects created prior to entering the WinEvent loop can be 
  2542. visually examined to determine if all objects are present. However, if within 
  2543. the WinEvent loop you open child windows based upon the user's dynamic input 
  2544. (i.e., clicking a button), then you might need to visually examine a large 
  2545. number of combinations to insure that every possible set of windows that could 
  2546. be created on the screen has the correct objects (i.e., that MaxButtons is 
  2547. large enough). Thus, while it is not too important to check error codes prior 
  2548. to the WinEvent loop (because all windows and objects are statically created 
  2549. and can be checked visually), within the WinEvent loop I'd recommend more 
  2550. careful error checking. 
  2551.  
  2552.  
  2553. In general, I always check for error conditions when a window is opened (i.e., 
  2554. BlankWin or OpenScrollWindow). When I call any other routine with dynamic 
  2555. parameters determined at run time (usually within the WinEvent loop), I also
  2556. check for error codes.
  2557.  
  2558.  
  2559. LangWin will generate a run-time error and abnormally terminate if any of the 
  2560. following conditions occur (routine names generating the error are given in 
  2561. parentheses): 
  2562.  
  2563. * MaxTextWins is greater than MaxWindows (LangWinInit)
  2564. * LBOUND of string array passed as a parameter is not 1 (OpenScrollWindow 
  2565.   and RefreshScrollText)
  2566. * Current window with focus has no scrollable text (RefreshScrollText)
  2567. * Invalid window handle passed as a parameter (NewFocusWindow)
  2568.  
  2569.  
  2570. All of the above conditions can be avoided by careful programming (unless, of 
  2571. course, Murphy is lurking nearby!). Refer to the corresponding member in 
  2572. WINHELP.BAS for more details on these errors.
  2573.  
  2574.  
  2575. 6.15 Testing for Color, B/W, EGA, or VGA 
  2576. ----------------------------------------
  2577. LangWin requires a color monitor and EGA or better graphics. Here's a technique 
  2578. for determining if your user is running on a system with a color or black and 
  2579. white monitor: 
  2580.  
  2581.     def seg = 0    ' low memory
  2582.     if peek(&h463) = &hB4 then mon$="b/w"
  2583.     if peek(&h463) = &hD4 then mon$="color"
  2584.     def seg
  2585.  
  2586. Determining whether EGA or better graphics exists is less straight forward. One 
  2587. technique is to use ON ERROR and to vary SCREEN modes (i.e., 12, 9). Depending 
  2588. on which mode (if any) causes an error, you can determine which color graphics 
  2589. support exists. I don't really like this technique. It's "brute force", but it 
  2590. works.
  2591.  
  2592. Another technique is to use BIOS interrupt 10h, functions 1Ah and 10h. I've 
  2593. had success with this technique, but my reference manuals say function 1Ah is 
  2594. for PS/2s. I've tried it on a non-PS/2 and it worked ok, but I can't say that 
  2595. it will work on every non-PS/2. To use this technique, first use the above 
  2596. test to determine if the monitor is color or b/w. Then call BIOS interrupt 10h 
  2597. function 1Ah. If the AX register is set to 1Ah upon return from the interrupt, 
  2598. then the function is supported by your BIOS. In that case, test the value of 
  2599. BX (4=EGA color, 5=EGA b/w, 7=VGA b/w, 8=VGA color). If AX is not set to 1Ah, 
  2600. then call BIOS interrupt 10h, function 12h, sub-function 10h. If BX is 
  2601. returned with a value of 1, then you have a b/w monitor. Else, if BX is not 
  2602. 10h, then you have EGA color. 
  2603.  
  2604.  
  2605. 6.16 Colors, Attributes, and Palettes
  2606. -------------------------------------
  2607. Throughout ALL of your code, you MUST use the SetColor routine instead of the 
  2608. COLOR command to change color attributes. The parameters are the same 
  2609. (foreground and background attributes) as the COLOR command. LangWin uses BIOS 
  2610. interrupt 10h, function 10h, sub-function 03h to disable blinking colors. This 
  2611. allows 16 attribute numbers for window (background) colors (rather than just 
  2612. 8). However, with blinking disabled, foreground and background attribute 
  2613. numbers MUST be translated before calling BASIC's COLOR command. SetColor does 
  2614. this translation and issues the COLOR command with the proper values. If 
  2615. BASIC's COLOR command is called without this translation, you will get 
  2616. unexpected colors. 
  2617.  
  2618. While in the QB development environment, if you interrupt your program under 
  2619. development, and use F4 to see the data displayed on the screen, you'll see 
  2620. blinking colors for background attribute numbers > 8. This is ok. As previously 
  2621. mentioned, LangWin disables the blinking bit and uses blinking background 
  2622. attributes (9-15) for additional colors. The QB environment, however, does not 
  2623. disable the blinking bit. So, when you hit F4 to see the screen, background 
  2624. attribute colors > 8 will blink. If you hit F5 to resume, the colors will still 
  2625. blink (because the blink bit is only disabled once in LangWinInit). If you 
  2626. restart your program (Shift-F4), then LangWinInit will again disable the 
  2627. blinking bit and colors will appear without blinking. 
  2628.  
  2629. LangWin supports 16 attributes (0-15) for colors. In text mode, however, you 
  2630. can assign up to 64 color values (0-63) to any given attribute number via the 
  2631. PALETTE command (i.e., PALETTE 5,27 assigns color number 27 to attribute 5). 
  2632. I've included a program called WINCOLOR on the distribution disk that will 
  2633. allow you to see all possible color values for various window entities. Once 
  2634. you find a set of colors values (as opposed to color attributes) that look 
  2635. good, then use PALETTE in your program to assign the color values to the 
  2636. attribute numbers coded in CALLs to LangWin routines. 
  2637.  
  2638. For example, MakePushButton requires two attributes as parameters (foreground 
  2639. and background of button). Assume you use attributes 2 and 3 for these 
  2640. parameters. Using WINCOLOR, you might determine that color values 23 and 41 
  2641. make pleasing foreground/background colors for your button (I just picked those 
  2642. two numbers at random and have no idea how they actually look). Using this 
  2643. example, you would code: PALETTE 2,23 (to set attribute 2 to color 23) and 
  2644. PALETTE 3,41 (to set attribute 3 to color 41). You would NOT need to modify 
  2645. your parameter list for MakePushButton (which would contain the attribute 
  2646. numbers 2 and 3). 
  2647.  
  2648. SAMPLE02.BAS has code that illustrates this technique. 
  2649.  
  2650.  
  2651. 6.17 WaitTicks
  2652. --------------
  2653. QuickBASIC has a command (SLEEP) that will allow your code to pause a given 
  2654. number of seconds. LangWin includes a routine (WaitTicks) that will allow your 
  2655. program to pause a given number of timer ticks (one timer tick is approximately 
  2656. 1/18.2 seconds). If you need finer granularity than seconds in a delay loop, 
  2657. use WaitTicks. 
  2658.  
  2659.  
  2660. 6.18 Video Pages
  2661. ----------------
  2662. If your video board has enough memory, you can display multiple video pages.
  2663. Refer to your BASIC documentation on the SCREEN command. With V2.3, LangWin 
  2664. will support windows in any video page that is available on your system; 
  2665. however, you MUST only use one video page consistently for all of LangWin's 
  2666. displays. That is, you should not switch video pages in the middle of a 
  2667. program that uses LangWin to display windows. This could cause unpredictable 
  2668. results. You MUST also define the video page via a SCREEN command BEFORE
  2669. the call to LangWinInit. 
  2670.  
  2671. LangWin keeps track of the coordinates of every object (button, check box, 
  2672. input field, etc.), but it does not remember the video page for these objects. 
  2673. LangWin assumes that all objects are in the same video page (I could add a 
  2674. feature to remember individual video pages for all objects, but LangWin's data 
  2675. structures are already getting too large). During initialization, LangWinInit 
  2676. obtains the current video page and saves this information in a global 
  2677. variable. All routines that read/write data directly in the video buffer use 
  2678. this global variable to place the data in the correct page. These routines 
  2679. will continue to write into the original video page regardless of the change 
  2680. in page number via the SCREEN command. However, some of LangWin's routines use 
  2681. the standard PRINT command to display data. These routines will display their 
  2682. data in the new video page. So, some data will be visible in the new page and 
  2683. some won't. Like I said, unpredictable results. 
  2684.  
  2685. In addition, if you change video pages with the SCREEN command, and happen to 
  2686. click on the coordinates of an object in the original page (which will be 
  2687. invisible at this point), LangWin will recognize the object and return control 
  2688. from WinEvent. Hitting enter will cause similar results with whatever object 
  2689. had focus (which might be on an invisible page). In these cases, your code 
  2690. will get control from WinEvent and process the event, even though the actual 
  2691. button might have been on an invisible page. Again, you could get 
  2692. unpredictable results. So, my advice is not to change video pages once the 
  2693. page number has been initially defined. 
  2694.  
  2695. The page number must be initially defined via a SCREEN 0,,x,x command (where x 
  2696. is a valid video page supported by your system). With V2.3, this command MUST 
  2697. be placed BEFORE the call to LangWinInit, which detects the video page and 
  2698. saves it in a global variable (actually the offset in the video buffer is 
  2699. saved in a global variable). See Section 3.1 for sample initialization code. 
  2700.  
  2701. There is one exception where changing video pages might be useful. If you plan 
  2702. to display data without the use of LangWin's routines, then you could change 
  2703. pages, display the data, then (when the user is finished with the data), 
  2704. change back to the page containing LangWin's display. For example, suppose you 
  2705. use LangWin to display a window with a scrollable list of file names. When the 
  2706. user clicks on a file name, you may want to display the file. One technique 
  2707. would be to change page numbers, use the SHELL command to exit to DOS and call 
  2708. a viewer to display the selected file. When the user exits the viewer, control 
  2709. would be returned from DOS back to your program at the point following the 
  2710. SHELL command. You would then reset the video page back to the original value 
  2711. and the scrollable list of files would again be visible. Before SHELLing to 
  2712. DOS to call the viewer, you should check for a mouse and hide the cursor. Upon 
  2713. return, check again and show the cursor. Here's a prototype of this example: 
  2714.  
  2715.  
  2716.         ' prior to this code, you would have detected a scrollable text click
  2717.         ' (action=2) in the appropriate window.
  2718.  
  2719.         i=WinParms(CurWinPtr,18)       ' index of clicked text block
  2720.         j=WinParms(CurWinPtr,15)       ' specific index of text line
  2721.         filespec$=SaveText(i,j)        ' text that was clicked
  2722.  
  2723.         IF HaveMouse THEN CALL HideMouseCursor   ' hide mouse
  2724.         SCREEN 0,,x,x                  ' set to new page (you must define x)
  2725.         SHELL "view "+filespec$        ' call viewer (assume its in your PATH)
  2726.         SCREEN 0,,z,z                  ' z is the original page number
  2727.         IF HaveMouse THEN CALL ShowMouseCursor   ' show mouse
  2728.  
  2729. The above code is only a prototype. It obviously depends upon exactly what
  2730. your viewer does. It's meant to give you an example of how you might use
  2731. multiple video pages with LangWin.
  2732.  
  2733. As an alternative to changing pages when shelling to an external program, you 
  2734. could open a window that covered the full screen. This would cause the entire 
  2735. screen's contents to be saved. Upon return from the external program, just 
  2736. close the current window. At that point, whatever the external program left on 
  2737. the screen would be visible; however, closing the current window would force 
  2738. LangWin to restore the contents of the screen "underneath" the last window 
  2739. opened. Since the last window opened covered the full screen, the effect of 
  2740. closing it would be to restore the entire screen (containing all windows that 
  2741. existed prior to shelling to the external program). The following code 
  2742. implements this technique for the file viewer example: 
  2743.  
  2744.         ' prior to this code, you would have detected a scrollable text click
  2745.         ' (action=2) in the appropriate window.
  2746.  
  2747.         i=WinParms(CurWinPtr,18)       ' index of clicked text block
  2748.         j=WinParms(CurWinPtr,15)       ' specific index of text line
  2749.         filespec$=SaveText(i,j)        ' text that was clicked
  2750.  
  2751.         IF HaveMouse THEN CALL HideMouseCursor   ' hide mouse
  2752.  
  2753.         xx=BlankWin(1,1,MaxRows,MaxCols,0,0,1,0,0,-1)
  2754.         ' the above code will open a window that covers the entire screen.
  2755.         ' the window's color will be 0 (black).
  2756.         ' MaxRows and MaxCols are global variables defined by your initial 
  2757.         ' call to LangWinInit.
  2758.         ' the effect will look like the screen has been cleared.
  2759.         ' the purpose of this call to BlankWin is to cause the contents
  2760.         ' of the screen "under" the window to be saved. that is, the
  2761.         ' entire screen will be saved. when this window is subsequently 
  2762.         ' closed, the screen's contents will be restored.
  2763.  
  2764.         SHELL "view "+filespec$        ' call viewer (assume its in your PATH)
  2765.         x=CloseWindow                  ' close full screen window which will
  2766.                                        ' restore the screen
  2767.         IF HaveMouse THEN CALL ShowMouseCursor   ' show mouse
  2768.  
  2769.  
  2770. 6.19 Using Non-Text Mode Graphics With LangWin
  2771. ----------------------------------------------
  2772. It is possible to "jump" into non-text mode graphics (i.e., SCREEN 9, 
  2773. SCREEN 13, etc.) then back to text mode (i.e., SCREEN 0). However, be aware
  2774. that when you jump to graphics mode, the screen will be cleared. I'll show you 
  2775. a technique for restoring the screen once you return to text mode, but when 
  2776. you jump from text to graphics, the contents of the screen (i.e., all windows 
  2777. and objects that have been displayed) will be cleared (but not lost). When you 
  2778. jump back from graphics mode to text mode, the contents of the graphics screen
  2779. will be cleared and lost (unless you manually save the screen yourself).
  2780. Finally, remember that LangWin's routines cannot be used while in graphics
  2781. modes.
  2782.  
  2783. Assume that you have opened some windows and placed objects in those windows.
  2784. Also assume that you are in the loop that calls WinEvent and tests for the
  2785. window number and action code. Depending upon a specific action (say a button 
  2786. click), assume you need to go into SCREEN mode 9, display some graphics, get 
  2787. user input, and then return to text mode. When you return to text mode, you 
  2788. want to see all windows and objects that existed before going to graphics 
  2789. mode. The following prototype code can be used:
  2790.  
  2791.         ' you determine that graphics mode is needed
  2792.  
  2793.         xx=BlankWin(1,1,MaxRows,MaxCols,0,0,1,0,0,-1)
  2794.         ' the above code will open a window that covers the entire screen.
  2795.         ' the window's color will be 0 (black).
  2796.         ' MaxRows and MaxCols are global variables defined by your initial 
  2797.         ' call to LangWinInit.
  2798.         ' the effect will look like the screen has been cleared.
  2799.         ' the purpose of this call to BlankWin is to cause the contents
  2800.         ' of the screen "under" the window to be saved. that is, the
  2801.         ' entire screen will be saved. when this window is subsequently 
  2802.         ' closed, the screen's contents will be restored.
  2803.  
  2804.         SCREEN 9   ' jump to graphics mode (this will actually cause the
  2805.                    ' the screen to be cleared. since it's already black,
  2806.                    ' clearing a second time won't be noticed).
  2807.  
  2808.         ' do your thing in graphics mode
  2809.  
  2810.         SCREEN 0    ' back to text mode. contents of graphics screen will be
  2811.                     ' cleared
  2812.  
  2813.         WIDTH MaxCols, MaxRows    ' reset rows/cols
  2814.         ' MaxRows and MaxCols are global variables defined by your initial 
  2815.         ' call to LangWinInit.
  2816.         
  2817.         CALL BlinkOff
  2818.         ' the BlinkOff subroutine is included in LangWin. its purpose is to
  2819.         ' tell the BIOS to turn off the blink bit in the color attribute
  2820.         ' (see Section 6.16 for additional information). if you don't
  2821.         ' call BlinkOff here, and you've used any background color attributes
  2822.         ' greater than 7, then these colors will blink when your windows
  2823.         ' are restored
  2824.  
  2825.         CALL SetTextCursor(DefaultSmask, DefaultCmask)
  2826.         ' the above code will set the mouse text mode cursor to a white
  2827.         ' arrow on a black background. DefaultSmask and DefaultCmask are
  2828.         ' global variables defined by your initial call to LangWinInit.
  2829.  
  2830.         CALL ShowMouseCursor  ' re-enable the mouse cursor
  2831.  
  2832.         xx=CloseWindow
  2833.         ' the above code will close the window that covered the screen.
  2834.         ' this will restore the screen's contents.
  2835.         ' your windows and objects should appear just as they did before
  2836.         ' jumping to graphics mode
  2837.  
  2838.  
  2839. 6.20 Closing Windows
  2840. --------------------
  2841. Normally, you'd just call CloseWindow to close the current window with focus.
  2842. However, you may need to close some other window, or you may not be sure
  2843. that the window you want to close has focus (remember, the used could click on 
  2844. any window and give it focus). Assume that you know the number of the window 
  2845. to be closed (the window number is returned by the function used to open it).
  2846. If the window's number is saved in variable WN, then the following technique 
  2847. can be used to make sure that the window has focus before calling CloseWindow:
  2848.  
  2849.     IF IsWinOpen(WN,han) THEN   ' if window is open, get its handle --> han
  2850.        zz=CurWinPtr             ' save handle of current window with focus      
  2851.        CALL NewFocusWindow(han) ' make the target window active
  2852.        x=CloseWindow            ' and close it
  2853.        CALL NewFocusWindow(zz)  ' return focus to original window
  2854.     END IF 
  2855.  
  2856. If you wanted to close several windows, and you did not know which
  2857. (if any) were open, you'd have to repeat the above code for each possible
  2858. window number to make sure all windows were closed. In this case, you could
  2859. just save the current window's handle once [ zz=CurWinPtr ] and restore it 
  2860. after all windows were closed [ CALL NewFocusWindow(zz) ].
  2861.  
  2862. There's another "short-cut" you can use if you just want to close ALL open
  2863. windows (if you want to close a sub-set of all possible windows, you'll have
  2864. to use the above technique with the numbers of each window to be closed).
  2865. To easily close ALL open windows:
  2866.  
  2867.     FOR i = LastWinStack TO 1 STEP -1
  2868.         CALL NewFocusWindow(WinStack(i))
  2869.         x=CloseWindow
  2870.     NEXT
  2871.  
  2872. The WinStack array contains the handles of all open windows, in the order
  2873. in which they appear on the screen. LastWinStack is a global variable pointing 
  2874. to the current slot. Thus WinStack(1) contains the handle of the first window
  2875. opened, and WinStack(LastWinStack) contains the handle of the window with 
  2876. focus. The above code just closes each window, from the most current to the 
  2877. least current.
  2878.  
  2879.  
  2880. 6.21 Modifying Static Text Created With ShowWinText
  2881. ---------------------------------------------------
  2882. The ShowWinText function is used to place static text in a window. Parameters 
  2883. include relative row/column (within the window) where the text is to be 
  2884. placed, text color, and text contents. The static text can be modified/changed 
  2885. by calling ShowWinText with the same row/column but new text. This is 
  2886. acceptable when only a few updates are needed. However, if the static text is 
  2887. modified based upon some user action (like a button click), then there is no 
  2888. way to determine the number of times the text will be modified. Each time 
  2889. ShowWinText is called, the text is saved in LangWin's data structures 
  2890. (ButtonsText and ButtonsData). These structures have a finite dimension 
  2891. (MaxButtons). Each call to ShowWinText requires a new entry in the data 
  2892. structures. Thus, repeated calls to modify text can exhaust all available 
  2893. slots. In this case, the result would be that subsequent calls to create 
  2894. objects (either new buttons, input fields, check boxes, or static text) will 
  2895. fail and the object will not appear. Closing a window will free all slots 
  2896. occupied by its objects. Increasing the value of MaxButtons will make more 
  2897. slots available. However, neither of these is a good solution. A better 
  2898. solution is to re-use the same slot whenever existing static text is modified. 
  2899. All that is needed is to first determine the slot number (handle) of the 
  2900. static text, then to update the contents of the existing slot and re-display 
  2901. it.
  2902.  
  2903. Since ShowWinText returns an error code and not the handle of the slot used to 
  2904. store text, you'll need to find and save the handle number in order to later 
  2905. modify its contents. The best way to do this is to use ShowWinText to 
  2906. temporarily place some specific text into the data structures, then manually 
  2907. scan the data structure until you find the specific text. The following code 
  2908. will accomplish these tasks: 
  2909.  
  2910.  
  2911.         x=ShowWinText(r,c,colr,"SOME UNIQUE TEXT")
  2912.         ' the above will place "SOME UNIQUE TEXT" at row=r, column=c in the
  2913.         ' current window using color=colr. the string "SOME UNIQUE TEXT"
  2914.         ' will also be placed into the next available slot in ButtonsText
  2915.         IF x < 0 THEN
  2916.            ' if error condition, process it
  2917.            END
  2918.         END IF
  2919.  
  2920.         thandle = -999   ' set a default value for the handle
  2921.         
  2922.         ' now search ButtonsText for the specific text string
  2923.         FOR i = 1 TO MaxButtons
  2924.             IF ButtonsText(i) = "SOME UNIQUE TEXT" THEN
  2925.                 thandle=i   ' save handle number
  2926.                 EXIT FOR    ' quit serach
  2927.             END IF
  2928.         NEXT
  2929.  
  2930.         ' just in case the "impossible" happens
  2931.         IF thandle = -999 THEN
  2932.                 ' process the error
  2933.                 END
  2934.         END IF
  2935.  
  2936. At this point, the variable:  thandle  points to the slot in LangWin's data 
  2937. structures that contains the temporary static text. The screen itself displays 
  2938. the temporary text at the designated row/column. Now, you must replace the 
  2939. temporary text with the initial value of the static text (using the same slot
  2940. in the data structures) and display this text on the screen. The following 
  2941. code will accomplish these tasks: 
  2942.  
  2943.         a$="initial contents of static text field"
  2944.         ButtonsText(thandle)=a$          ' update text in data structure
  2945.         CALL ReShowInputField(thandle)   ' redisplay text on screen
  2946.         ButtonsData(thandle,4) = LEN(a$) ' update length of text area
  2947.         
  2948. You might ask: why is the length of the text in LangWin's data structure 
  2949. updated AFTER the text is displayed? Glad you asked that question! 
  2950. ReShowInputField (which is really meant to redisplay the contents of an input 
  2951. field after it has been modified, but will also redisplay static text) first 
  2952. clears the entire contents of the area, then displays the new text. The length 
  2953. of the area to clear is obtained from the data structure. So, if the length of 
  2954. the new text was smaller than the previous text, and the new (smaller) length 
  2955. was first placed into the data structure, then only the smaller area would 
  2956. cleared prior to displaying the new text. Any characters from the previous 
  2957. (longer) text beyond the end of the new (smaller) text would remain on the 
  2958. screen. By calling ReShowInputField before the length is updated, the length 
  2959. of the area cleared will correspond to the the current text. 
  2960.  
  2961. Later in your program, when you determine that new static text must be 
  2962. placed into the window at the same position as the old text, the following 
  2963. code can be used: 
  2964.  
  2965.         a$="new contents of static text field"
  2966.         ButtonsText(thandle)=a$          ' update text in data structure
  2967.         CALL ReShowInputField(thandle)   ' redisplay text on screen
  2968.         ButtonsData(thandle,4) = LEN(a$) ' update length of text area
  2969.  
  2970. These techniques can be used with any number of static text entries. You'll
  2971. just need to save each handle in a unique variable name.
  2972.  
  2973.  
  2974. 6.22 "Time Out" Feature of WinEvent for Interrupt Buttons 
  2975. ---------------------------------------------------------
  2976. Normally, when you call WinEvent, your program only regains control when 
  2977. WinEvent detects an event. If no event occurs, WinEvent retains control, and 
  2978. your program cannot do any work. In most cases, this is ok. You don't need to 
  2979. do any work until an event occurs in a window. Then, your program will get 
  2980. control from WinEvent, determine the window and the event that occurred, take 
  2981. the appropriate actions, and return control to WinEvent to determine the next 
  2982. event in the window. 
  2983.  
  2984. However, if the action you take involves starting a long running task, then 
  2985. WinEvent will not be given control until this long running task completes, and 
  2986. there is no way to interrupt the long running task (because WinEvent will not 
  2987. have control, events in the window, like button clicks, will not be detected). 
  2988.  
  2989. This is where the "time out" feature of WinEvent comes in. With the "time out" 
  2990. feature enabled, if no event occurs within 0.5 seconds, WinEvent will return 
  2991. control to your program. WinEvent is called with one parameter (the action 
  2992. code). Prior to returning control to your program, WinEvent sets this action 
  2993. code based upon the event that was detected (1 = close, 2 = text click, 3 = 
  2994. button click). To enable the time out feature, call WinEvent with the action 
  2995. code variable set to -999 (any other value for the the action code will have no 
  2996. effect on WinEvent). If an event occurs, the action code variable is set 
  2997. appropriately. If no event occurs, and the action code was -999, control will 
  2998. be returned after 0.5 seconds (and the action code will remain set to -999). 
  2999. WARNING: do not call WinEvent(-999) to enable the time out. You must call 
  3000. WinEvent with a variable since this variable will be set if an event occurs. 
  3001. To enable the time out feature, call WinEvent as follows: 
  3002.  
  3003.         ActCode=-999
  3004.         wn=WinEvent(ActCode)
  3005.  
  3006. In order to interrupt a long running task, place the task in a loop with a 
  3007. call to WinEvent (with time out feature enabled). Each time through the loop, 
  3008. some portion of the long running task is completed (like reading one record 
  3009. from a large file, scanning one directory, whatever portion of the overall 
  3010. task that is appropriate). After completing a portion of the long running 
  3011. task, call WinEvent with the time out feature. After the call to WinEvent, 
  3012. determine what (if any) event occurred. If the event was a click on your 
  3013. interrupt button, exit the loop that processed the long running task. If no 
  3014. event occurred (i.e., WinEvent timed out after 0.5 seconds), then loop and 
  3015. perform more work on the long running task. 
  3016.  
  3017. Here's some pseudo code. Assume this code gets control when a "start" button 
  3018. is clicked to initiate the long running task. Also assume that prior to this 
  3019. point, a MODAL window was opened with start and interrupt buttons for the
  3020. long running task. Finally, assume that the long running task is to read all
  3021. records from a file. 
  3022.  
  3023.         CASE StartButton
  3024.             deactivate "start" button (don't need it now)
  3025.             activate "interrupt" button (assume it was previously inactive)
  3026.             open a file (assume the long running task is to read a file)
  3027.  
  3028.             ' process long running task
  3029.             DO
  3030.                 read a record (assume the long running task is to read a file)
  3031.                 update screen to show some kind of progress
  3032.                 if EOF then EXIT DO  ' see if task is done
  3033.                 act=-999             ' to activate time out feature
  3034.                 wn=WinEvent(act)     ' get an action or time out 
  3035.             LOOP UNTIL interrupt button action detected
  3036.  
  3037.             ' long running task completed or interrupted
  3038.             
  3039.             deactivate "interrupt" button (not needed now)
  3040.             activate the "start" button (if it's needed)
  3041.             close file
  3042.             process the data
  3043.             close the current window (if it's no longer needed)
  3044.  
  3045.  
  3046. Note that you should not attempt to do too much work in your loop before 
  3047. periodically giving control to WinEvent (to see if the interrupt button was 
  3048. clicked). WinEvent is not aware of mouse clicks made before it is called. This 
  3049. is because it must hide and re-show the mouse cursor during initialization 
  3050. (which causes the mouse driver to zero the mouse press counter). Thus, if you 
  3051. do a lot of processing before calling WinEvent, your user could have been 
  3052. attempting to click the interrupt button for awhile with no response. You'll 
  3053. have to experiment, and tune your code so that it gets back to WinEvent 
  3054. quickly. If you notice that the interrupt button needs to be clicked very 
  3055. frequently before it is recognized, then the cause is probably due to an 
  3056. excessive amount of time consumed by your task in between iterations of the 
  3057. loop where WinEvent is called. 
  3058.  
  3059. I strongly recommend that the window you open, with buttons to start and 
  3060. interrupt the long running task, be MODAL (that is, only events in that window 
  3061. will be recognized by WinEvent, events in other windows will be ignored). The 
  3062. "in-line" call to WinEvent (in the loop that processes your long running task) 
  3063. will restrict the events recognized by your program to just those that you 
  3064. explicitly test for after returning from WinEvent (the code you have elsewhere 
  3065. in your program to handle other buttons in other windows will not be given 
  3066. control). If the window with the start and interrupt buttons is not modal, 
  3067. then your user will be able to mouse to other windows, make them active, and 
  3068. click their buttons. This will have visual effects (active windows will move 
  3069. to the top, clicked buttons will move); however, unless explicit code to 
  3070. handle these events (in other windows) is included in your loop with the long 
  3071. running task, the clicks on other buttons will be ignored. This will confuse 
  3072. your user. By making the window with the start and interrupt buttons modal, 
  3073. your user will not be able to mouse to another window to make it active, and 
  3074. clicking objects on other windows will show no visual effect. 
  3075.  
  3076. See SAMPLE05.BAS for an example of the technique for using WinEvent's time out 
  3077. feature to implement an interrupt button. 
  3078.  
  3079.  
  3080. 6.23 Dynamically Adding Entries to a Visible List of Scrollable Text
  3081. --------------------------------------------------------------------
  3082. The OpenScrollWindow function is used to create a window with scrollable text. 
  3083. After the window is opened, you may want to add entries to the end of this list 
  3084. in real-time and display these new entries in the visible window. 
  3085.  
  3086. The GrowScrollText function will accomplish this task. This function takes one 
  3087. parameter: a text string. The contents of this text string is appended to the 
  3088. end of the scrollable text array associated with the current window, and the 
  3089. visible text in the window is re-displayed. The nature of that re-display 
  3090. depends upon whether or not the existing scrollable text fills the text area 
  3091. defined for the window. 
  3092.  
  3093. If the list of scrollable text in the current window does not fill the text 
  3094. area defined when the window was opened, then the text string passed to 
  3095. GrowScrollText will be be displayed at the bottom of the visible list. If the 
  3096. list of scrollable text fills the text area, then text is scrolled up and the 
  3097. new string passed to GrowScrollText is displayed at the bottom of the text 
  3098. area. Note that the list of scrollable text could be null, in which case the 
  3099. first call to GrowScrollText will create the first line of scrollable text in 
  3100. the current window (but a scrollable text window must have been opened, 
  3101. otherwise GrowScrollText will not work properly). 
  3102.  
  3103. GrowScrollText will operate on the current window with focus. If that window 
  3104. is not a scrollable text window, no action is taken and an error code (-1) is 
  3105. returned (i.e., even if the scrollable text array is null, the window MUST 
  3106. have been opened with OpenScrollText and NOT with BlankWin). If the scrollable 
  3107. text array for the current window is already full (i.e., it has MaxTextLines 
  3108. lines of text already defined), no action is taken and an error code (-2) is 
  3109. returned. 
  3110.  
  3111. GrowScrollText can be used to give the user visual feedback as a long running 
  3112. task progresses. Suppose you have a routine that searches for specific records 
  3113. in a data base, and you want to display these in a scrollable list for your 
  3114. user to browse. GrowScrollText can be used to show the records being 
  3115. dynamically added to the list as they are found. The following pseudo code 
  3116. will implement this example: 
  3117.  
  3118.  
  3119.    Dim Text(1 to 1) AS STRING  ' scrollable text, init as null
  3120.    ' The above array need only have 1 entry (initiallized to null).
  3121.    ' It's only used by OpenScrollWindow to initialize LangWin's data structure
  3122.    ' SaveText. Thereafter, the scrollable text is actually "grown" in SaveText.
  3123.             .
  3124.             .
  3125.    w1=OpenScrollWindow( ..... ,Text(), .....) 'scrollable window with null text
  3126.    ' put some buttons in the window
  3127.             .
  3128.             .
  3129.    DO WHILE AnyWinOpen         ' process windows
  3130.         wn=WinEvent(action)       ' wait for an action
  3131.         ' process actions in windows
  3132.              .
  3133.              .
  3134.              .
  3135.  
  3136.         ' assume that at this point you determine the need to search a 
  3137.         ' database for records, and to display the results in a scrollable
  3138.         ' window (w1) where the user can browse the results.
  3139.  
  3140.         ' w1 is the number of the open window that will contain the 
  3141.         ' scrollable text. at this point, the scrollable text array is null.
  3142.         x=IsWinOpen(w1,Han)     ' get handle of w1 and save in Han
  3143.  
  3144.         ' search loop
  3145.         DO
  3146.             ' first, you must make sure window with text (w1) is current
  3147.             CALL NewFocusWindow(Han)   ' give focus to text window
  3148.             
  3149.             rec$=GetNextMatch$(parms)  ' get a record  
  3150.             IF rec$="" THEN EXIT DO    ' see if search is done
  3151.             ' note: GetNextMatch$ is NOT part of LangWin. it's
  3152.             ' a fictitious function used to illustrate a routine
  3153.             ' that you might call to get a record and return in text string.
  3154.             ' i assume a null value is returned when search is completed.
  3155.  
  3156.             rc=GrowScrollText(rec$)     ' display rec in window
  3157.             SELECT CASE rc  ' test above return code
  3158.             CASE -1   ' current window is not a scrollable text window
  3159.                 ' process the error
  3160.             CASE -2   ' scrollable text array is full
  3161.                ' process the error. this might include allowing
  3162.                ' the user to browse the scrollable text and waiting
  3163.                ' for a CONTINUE button to be clicked. when this
  3164.                ' button is clicked, you could close the window,
  3165.                ' re-open it (to clear text), and continue the search.
  3166.             END SELECT
  3167.  
  3168.             ' using the time-out techniques from Section 6.22, you could 
  3169.             ' also include a STOP button to interrupt the search.
  3170.             ' assume handle of STOP button is: Stop1
  3171.             aa=-999          ' set time out option
  3172.             x=WinEvent(aa)   ' wait for 0.5 sec for an event
  3173.         ' loop until STOP button is clicked 
  3174.         LOOP UNTIL (aa=3 AND WinParms(CurWinPtr,16)=Stop1)
  3175.  
  3176. See SAMPLE05.BAS for actual code that used GrowScrollText.
  3177.  
  3178.  
  3179.  
  3180. ------------------
  3181. 7.0 MOUSE ROUTINES 
  3182. ------------------
  3183. LangWin has several general mouse routines that can be used to control the 
  3184. mouse and get status. These are documented in WINHELP.BAS and include: 
  3185.  
  3186.          MouseExists     - test to see if mouse driver is installed
  3187.          InitMouse       - initialize the mouse
  3188.          
  3189.          GetButtonPress  - get position of mouse when a button was last clicked
  3190.          GetMousePos     - get current position of mouse
  3191.          SetMousePos     - set current position of mouse
  3192.          
  3193.          SetXLimit       - set horizontal limits of mouse
  3194.          SetYLimit       - set vertical limits of mouse
  3195.  
  3196.          ShowMouseCursor - make the mouse pointer visible
  3197.          HideMouseCursor - hide the mouse pointer
  3198.  
  3199. SAMPLE03.BAS contains sample code using the above routines. Load WINHELP.BAS 
  3200. into QB and hit F2 to see details on each of these routines. 
  3201.  
  3202.  
  3203.  
  3204. -------------------------------
  3205. 8.0 DIRECTORY AND FILE ROUTINES
  3206. -------------------------------
  3207. LangWin 2.0 has several functions that allow you to easily determine the 
  3208. current drive and directory, set the current drive and directory, and extract a 
  3209. list of files and sub-directories from the current directory. These are 
  3210. documented in WINHELP.BAS and include: 
  3211.  
  3212.  
  3213.          ChangeDir       - change the default directory on a specified drive
  3214.          ChangeDrive     - change the default drive
  3215.          GetCurDir$      - get the default directory on a specified drive
  3216.          GetCurDrive$    - get the default drive letter
  3217.          GetFileNames    - get either file names or sub-dir names from the
  3218.                            current directory and save them in a string array
  3219.  
  3220. SAMPLE04.BAS contains code that use these functions.
  3221.  
  3222.  
  3223.  
  3224.          
  3225. ----------------------
  3226. 9.0 COMING ATTRACTIONS
  3227. ----------------------
  3228. With LangWin 2.1, you now have a professional quality toolkit for creating a 
  3229. GUI in QuickBASIC. However, screen design with LangWin does leave a lot to be 
  3230. desired. You have to manually figure out all of the screen coordinates for your 
  3231. windows, and remember which parameters in what functions to use. LangWin 
  3232. now has the ability to load WINHELP.BAS, so at least you can review the 
  3233. parameter lists while you are developing. Still, it's a labor intensive process 
  3234. to design the screen. 
  3235.  
  3236. I am considering an graphical "front end" program that will allow you to design 
  3237. your screen interactively using the mouse. You'll click on the coordinates 
  3238. where windows are to be created, select colors, select objects from a menu and 
  3239. place them into the window. When you are satisfied, the "front end" will then 
  3240. generate the appropriate CALLs to LangWin routines. If you've read about or 
  3241. seen VBDOS, this should sound familiar. So, stay tuned for LangWin 3.0.
  3242.  
  3243.  
  3244.  
  3245. --------------------------
  3246. 10.0 CONTACTING THE AUTHOR
  3247. --------------------------
  3248. If you have any questions about LangWin, suggestions for improvement, or 
  3249. want to report a bug (ugh), send U.S. Mail to:
  3250.  
  3251.                 Allen Lang
  3252.                 121 Windsor Commons
  3253.                 Cranbury, NJ 08512
  3254.  
  3255. If you have access to Prodigy, my ID is: KJNX76A
  3256.  
  3257. Before reporting a bug, I'll need to know your version of LangWin.
  3258. I've included a routine to extract the version number (GetVerNum$).
  3259. Go into QuickBASIC's immediate window and enter:  print GetVerNum$
  3260.  
  3261. Before contacting me, I'd highly recommend that you: read ALL of the doc in 
  3262. this file, read the descriptions for all LangWin's routines (load WINHELP.BAS 
  3263. into QB and hit F2), and thoroughly examine the sample code included with this 
  3264. distribution. While that will require an investment of your time, you'll be 
  3265. able to fully utilize the power of LangWin, and you'll probably find the answer 
  3266. to most of your questions. Good luck and happy coding!!!
  3267.  
  3268.